Skip to content

Commit

Permalink
Merge branch 'develop' into keyboard-shortcuts
Browse files Browse the repository at this point in the history
  • Loading branch information
hatemhosny authored Jan 11, 2025
2 parents 9acf7bd + 2743dc6 commit 73cb1f4
Show file tree
Hide file tree
Showing 33 changed files with 187 additions and 17 deletions.
5 changes: 3 additions & 2 deletions docs/docs/configuration/configuration-object.md
Original file line number Diff line number Diff line change
Expand Up @@ -627,11 +627,12 @@ The number of spaces per indentation-level. Also used in [code formatting](../fe

### `lineNumbers`

Type: [`boolean`](../api/interfaces/Config.md#linenumbers)
Type: [`boolean | "relative"`](../api/interfaces/Config.md#linenumbers)

Default: `true`

Show line numbers in [code editor](../features/editor-settings.md).
Show line numbers in [code editor](../features/editor-settings.md).
If set to `"relative"`, line numbers are shown relative to the current line. This can be useful with [vim mode](#editormode).

### `wordWrap`

Expand Down
1 change: 1 addition & 0 deletions scripts/vendors.js
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,7 @@ const buildVendors = () => {
'codemirror-emacs.ts',
'codemirror-emmet.ts',
'codemirror-codeium.ts',
'codemirror-line-numbers-relative.ts',
'languages/codemirror-lang-json.ts',
'languages/codemirror-lang-markdown.ts',
'languages/codemirror-lang-python.ts',
Expand Down
56 changes: 47 additions & 9 deletions src/livecodes/UI/editor-settings.ts
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,10 @@ export const createEditorSettingsUI = async ({

interface FormField {
title?: string;
name: keyof UserConfig | `editorTheme-${Config['editor']}-${Config['theme']}`;
name:
| keyof UserConfig
| 'lineNumbersRelative'
| `editorTheme-${Config['editor']}-${Config['theme']}`;
options: Array<{ label?: string; value: string; checked?: boolean }>;
help?: string;
note?: string;
Expand Down Expand Up @@ -208,6 +211,14 @@ export const createEditorSettingsUI = async ({
name: 'lineNumbers',
options: [{ value: 'true' }],
},
{
title: window.deps.translateString(
'editorSettings.lineNumbersRelative',
'Relative line numbers *',
),
name: 'lineNumbersRelative',
options: [{ value: 'true' }],
},
{
title: window.deps.translateString('editorSettings.wordWrap', 'Word-wrap'),
name: 'wordWrap',
Expand Down Expand Up @@ -342,12 +353,14 @@ export const createEditorSettingsUI = async ({
form.appendChild(fieldContainer);

const name = `editor-settings-${field.name}`;
const optionValue = String(
(editorOptions as any)[field.name] ??
(userConfig as any)[field.name] ??
(defaultConfig as any)[field.name] ??
'',
);
const getOptionValue = (name: string) =>
String(
(editorOptions as any)[name] ??
(userConfig as any)[name] ??
(defaultConfig as any)[name] ??
'',
);
const optionValue = getOptionValue(field.name);

if (field.options.length > 4) {
const select = document.createElement('select');
Expand Down Expand Up @@ -400,7 +413,16 @@ export const createEditorSettingsUI = async ({
input.id = id;
input.value = option.value;
input.checked =
field.name === 'theme' ? optionValue === 'dark' : optionValue === option.value;
field.name === 'theme'
? optionValue === 'dark'
: field.name === 'lineNumbers'
? optionValue === 'true' || optionValue === 'relative'
: optionValue === option.value;

if (field.name === 'lineNumbersRelative') {
input.checked = getOptionValue('lineNumbers') === 'relative';
input.disabled = getOptionValue('lineNumbers') === 'false';
}

optionContainer.appendChild(input);

Expand Down Expand Up @@ -440,7 +462,7 @@ export const createEditorSettingsUI = async ({
? Number(value)
: value,
}),
{} as EditorOptions,
{} as EditorOptions & { lineNumbersRelative?: boolean },
);

const booleanFields = formFields
Expand All @@ -459,8 +481,24 @@ export const createEditorSettingsUI = async ({
if (key === 'theme') {
formData.theme = (formData.theme as any) === true ? 'dark' : 'light';
}
if (
key === 'lineNumbersRelative' &&
formData.lineNumbersRelative === true &&
formData.lineNumbers === true
) {
formData.lineNumbers = 'relative';
}
});

const relativeLineNumbersField = form.querySelector<HTMLInputElement>(
'[name="editor-settings-lineNumbersRelative"]',
);
if (relativeLineNumbersField) {
relativeLineNumbersField.checked = formData.lineNumbers === 'relative';
relativeLineNumbersField.disabled = formData.lineNumbers === false;
}
delete formData.lineNumbersRelative;

formData.editorTheme = allThemes
.map((name) => (formData as any)[name])
.filter(Boolean)
Expand Down
4 changes: 3 additions & 1 deletion src/livecodes/config/validate-config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -162,7 +162,9 @@ export const validateConfig = (config: Partial<Config>): Partial<Config> => {
...(is(config.fontSize, 'number') ? { fontSize: Number(config.fontSize) } : {}),
...(is(config.useTabs, 'boolean') ? { useTabs: config.useTabs } : {}),
...(is(config.tabSize, 'number') ? { tabSize: Number(config.tabSize) } : {}),
...(is(config.lineNumbers, 'boolean') ? { lineNumbers: config.lineNumbers } : {}),
...(is(config.lineNumbers, 'boolean') || config.lineNumbers === 'relative'
? { lineNumbers: config.lineNumbers }
: {}),
...(is(config.wordWrap, 'boolean') ? { wordWrap: config.wordWrap } : {}),
...(is(config.closeBrackets, 'boolean') ? { closeBrackets: config.closeBrackets } : {}),
...(is(config.semicolons, 'boolean') ? { semicolons: config.semicolons } : {}),
Expand Down
2 changes: 1 addition & 1 deletion src/livecodes/editor/codejar/codejar.ts
Original file line number Diff line number Diff line change
Expand Up @@ -334,7 +334,7 @@ export const createEditor = async (options: EditorOptions): Promise<CodeEditor>
`;
document.head.appendChild(styleEl);
setTheme(settings.theme, settings.editorTheme);
preElement.classList.toggle('line-numbers', editorOptions.lineNumbers);
preElement.classList.toggle('line-numbers', Boolean(editorOptions.lineNumbers));
highlight();
};
changeSettings(options);
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
// from https://github.com/jsjoeio/codemirror-line-numbers-relative

import { EditorView, type ViewUpdate, lineNumbers, gutter, GutterMarker } from '@codemirror/view';
import { Compartment, type EditorState, type Extension } from '@codemirror/state';

const relativeLineNumberGutter = new Compartment();

class Marker extends GutterMarker {
/** The text to render in gutter */
public text: string;

public constructor(text: string) {
super();
this.text = text;
}

public toDOM() {
return document.createTextNode(this.text);
}
}

const absoluteLineNumberGutter = gutter({
lineMarker: (view, line) => {
const lineNo = view.state.doc.lineAt(line.from).number;
const absoluteLineNo = new Marker(lineNo.toString());
const cursorLine = view.state.doc.lineAt(view.state.selection.asSingle().ranges[0].to).number;

if (lineNo === cursorLine) {
return absoluteLineNo;
}

return null;
},
initialSpacer: () => {
const spacer = new Marker('0');
return spacer;
},
});

function relativeLineNumbers(lineNo: number, state: EditorState) {
if (lineNo > state.doc.lines) {
return ' ';
}
const cursorLine = state.doc.lineAt(state.selection.asSingle().ranges[0].to).number;
if (lineNo === cursorLine) {
return ' ';
} else {
return Math.abs(cursorLine - lineNo).toString();
}
}
// This shows the numbers in the gutter
const showLineNumbers = relativeLineNumberGutter.of(
lineNumbers({ formatNumber: relativeLineNumbers }),
);

// This ensures the numbers update
// when selection (cursorActivity) happens
const lineNumbersUpdateListener = EditorView.updateListener.of((viewUpdate: ViewUpdate) => {
if (viewUpdate.selectionSet) {
viewUpdate.view.dispatch({
effects: relativeLineNumberGutter.reconfigure(
lineNumbers({ formatNumber: relativeLineNumbers }),
),
});
}
});

export function lineNumbersRelative(): Extension {
return [absoluteLineNumberGutter, showLineNumbers, lineNumbersUpdateListener];
}
13 changes: 11 additions & 2 deletions src/livecodes/editor/codemirror/codemirror.ts
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,7 @@ export const createEditor = async (options: EditorOptions): Promise<CodeEditor>
let codeium:
| ((editors: CodeiumEditor[], mapLanguage: (lang: Language) => Language) => Extension)
| undefined;
let lineNumbersRelative: () => Extension;

const configureTSExtension = (extensionList: readonly Extension[]) => {
if (mappedLanguage === 'typescript') {
Expand Down Expand Up @@ -170,17 +171,20 @@ export const createEditor = async (options: EditorOptions): Promise<CodeEditor>
emacs: `./vendor/codemirror/${process.env.codemirrorVersion}/codemirror-emacs.js`,
emmet: `./vendor/codemirror/${process.env.codemirrorVersion}/codemirror-emmet.js`,
codeium: `./vendor/codemirror/${process.env.codemirrorVersion}/codemirror-codeium.js`,
lineNumbersRelative: `./vendor/codemirror/${process.env.codemirrorVersion}/codemirror-line-numbers-relative.js`,
};
const [vimMod, emacsMod, emmetMod, codeiumMod] = await Promise.all([
const [vimMod, emacsMod, emmetMod, codeiumMod, lineNumbersRelativeMod] = await Promise.all([
opt.editorMode === 'vim' ? import(modules.vim) : Promise.resolve({}),
opt.editorMode === 'emacs' ? import(modules.emacs) : Promise.resolve({}),
opt.emmet ? import(modules.emmet) : Promise.resolve({}),
opt.enableAI ? import(modules.codeium) : Promise.resolve({}),
opt.lineNumbers === 'relative' ? import(modules.lineNumbersRelative) : Promise.resolve({}),
]);
vim = vimMod.vim;
emacs = emacsMod.emacs;
emmet = emmetMod.emmet;
codeium = codeiumMod.codeium;
lineNumbersRelative = lineNumbersRelativeMod.lineNumbersRelative;
};
await loadExtensions(options);

Expand All @@ -201,6 +205,7 @@ export const createEditor = async (options: EditorOptions): Promise<CodeEditor>
const useTabs = settings.useTabs ?? editorSettings.useTabs;
const wordWrap = settings.wordWrap ?? editorSettings.wordWrap;
const enableEmmet = settings.emmet ?? editorSettings.emmet;
const enableLineNumbers = settings.lineNumbers ?? editorSettings.lineNumbers;
const enableAI = settings.enableAI ?? editorSettings.enableAI;
const editorMode = settings.editorMode ?? editorSettings.editorMode;

Expand All @@ -210,6 +215,11 @@ export const createEditor = async (options: EditorOptions): Promise<CodeEditor>
...(wordWrap ? [EditorView.lineWrapping] : []),
...(editorMode === 'vim' && vim ? [vim()] : editorMode === 'emacs' && emacs ? [emacs()] : []),
...(enableEmmet && emmet ? [emmet] : []),
...(enableLineNumbers === 'relative' && lineNumbersRelative
? [lineNumbersRelative()]
: enableLineNumbers && lineNumbers
? [lineNumbers()]
: []),
...(enableAI && codeium ? [codeium(editors, mapLanguage)] : []),
EditorView.theme({
'&': {
Expand Down Expand Up @@ -237,7 +247,6 @@ export const createEditor = async (options: EditorOptions): Promise<CodeEditor>
syntaxHighlighting(italicComments),
editorSettingsExtension.of(configureSettingsExtension({})),
keyBindingsExtension.of(keymap.of(keyBindings)),
lineNumbersExtension.of(editorSettings.lineNumbers ? lineNumbers() : []),
closeBracketsExtension.of(editorSettings.closeBrackets ? closeBrackets() : []),
basicSetup,
readonly ? readOnlyExtension : [],
Expand Down
2 changes: 1 addition & 1 deletion src/livecodes/editor/monaco/monaco.ts
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,7 @@ export const createEditor = async (options: EditorOptions): Promise<CodeEditor>
insertSpaces: !opt.useTabs,
detectIndentation: false,
tabSize: opt.tabSize,
lineNumbers: opt.lineNumbers ? 'on' : 'off',
lineNumbers: opt.lineNumbers === 'relative' ? 'relative' : opt.lineNumbers ? 'on' : 'off',
wordWrap: opt.wordWrap ? 'on' : 'off',
autoClosingBrackets: opt.closeBrackets ? 'always' : 'never',
autoClosingQuotes: opt.closeBrackets ? 'always' : 'never',
Expand Down
3 changes: 3 additions & 0 deletions src/livecodes/i18n/locales/ar/translation.lokalise.json
Original file line number Diff line number Diff line change
Expand Up @@ -756,6 +756,9 @@
"editorSettings.lineNumbers": {
"translation": "إظهار أرقام الأسطر"
},
"editorSettings.lineNumbersRelative": {
"translation": "أرقام الأسطر النسبية*"
},
"editorSettings.notAvailableInCodeJar": {
"translation": "غير متوفر في CodeJar"
},
Expand Down
1 change: 1 addition & 0 deletions src/livecodes/i18n/locales/ar/translation.ts
Original file line number Diff line number Diff line change
Expand Up @@ -429,6 +429,7 @@ const translation: I18nTranslation = {
format: 'تنسيق',
heading: 'إعدادات المحرر',
lineNumbers: 'إظهار أرقام الأسطر',
lineNumbersRelative: 'أرقام الأسطر النسبية*',
notAvailableInCodeJar: 'غير متوفر في CodeJar',
preview: 'معاينة',
semicolons: 'التنسيق: استخدام الفواصل المنقوطة',
Expand Down
3 changes: 3 additions & 0 deletions src/livecodes/i18n/locales/de/translation.lokalise.json
Original file line number Diff line number Diff line change
Expand Up @@ -756,6 +756,9 @@
"editorSettings.lineNumbers": {
"translation": "Zeilennummern anzeigen"
},
"editorSettings.lineNumbersRelative": {
"translation": "Relative Zeilennummern *"
},
"editorSettings.notAvailableInCodeJar": {
"translation": "Nicht verfügbar in CodeJar"
},
Expand Down
1 change: 1 addition & 0 deletions src/livecodes/i18n/locales/de/translation.ts
Original file line number Diff line number Diff line change
Expand Up @@ -429,6 +429,7 @@ const translation: I18nTranslation = {
format: 'Format',
heading: 'Editor-Einstellungen',
lineNumbers: 'Zeilennummern anzeigen',
lineNumbersRelative: 'Relative Zeilennummern *',
notAvailableInCodeJar: 'Nicht verfügbar in CodeJar',
preview: 'Vorschau',
semicolons: 'Format: Semikolons verwenden',
Expand Down
4 changes: 4 additions & 0 deletions src/livecodes/i18n/locales/en/translation.lokalise.json
Original file line number Diff line number Diff line change
Expand Up @@ -1280,6 +1280,10 @@
"notes": "",
"translation": "Show line numbers"
},
"editorSettings.lineNumbersRelative": {
"notes": "",
"translation": "Relative line numbers *"
},
"editorSettings.notAvailableInCodeJar": {
"notes": "",
"translation": "Not available in CodeJar"
Expand Down
1 change: 1 addition & 0 deletions src/livecodes/i18n/locales/en/translation.ts
Original file line number Diff line number Diff line change
Expand Up @@ -514,6 +514,7 @@ const translation = {
format: 'Format',
heading: 'Editor Settings',
lineNumbers: 'Show line numbers',
lineNumbersRelative: 'Relative line numbers *',
notAvailableInCodeJar: 'Not available in CodeJar',
preview: 'Preview',
semicolons: 'Format: Use Semicolons',
Expand Down
3 changes: 3 additions & 0 deletions src/livecodes/i18n/locales/es/translation.lokalise.json
Original file line number Diff line number Diff line change
Expand Up @@ -756,6 +756,9 @@
"editorSettings.lineNumbers": {
"translation": "Mostrar números de línea"
},
"editorSettings.lineNumbersRelative": {
"translation": "Números de línea relativos *"
},
"editorSettings.notAvailableInCodeJar": {
"translation": "No disponible en CodeJar"
},
Expand Down
1 change: 1 addition & 0 deletions src/livecodes/i18n/locales/es/translation.ts
Original file line number Diff line number Diff line change
Expand Up @@ -429,6 +429,7 @@ const translation: I18nTranslation = {
format: 'Formato',
heading: 'Configuración del editor',
lineNumbers: 'Mostrar números de línea',
lineNumbersRelative: 'Números de línea relativos *',
notAvailableInCodeJar: 'No disponible en CodeJar',
preview: 'Vista previa',
semicolons: 'Formato: Usar punto y coma',
Expand Down
3 changes: 3 additions & 0 deletions src/livecodes/i18n/locales/fr/translation.lokalise.json
Original file line number Diff line number Diff line change
Expand Up @@ -756,6 +756,9 @@
"editorSettings.lineNumbers": {
"translation": "Afficher les numéros de ligne"
},
"editorSettings.lineNumbersRelative": {
"translation": "Numéros de ligne relatifs *"
},
"editorSettings.notAvailableInCodeJar": {
"translation": "Non disponible dans CodeJar"
},
Expand Down
1 change: 1 addition & 0 deletions src/livecodes/i18n/locales/fr/translation.ts
Original file line number Diff line number Diff line change
Expand Up @@ -429,6 +429,7 @@ const translation: I18nTranslation = {
format: 'Format',
heading: "Paramètres de l'éditeur",
lineNumbers: 'Afficher les numéros de ligne',
lineNumbersRelative: 'Numéros de ligne relatifs *',
notAvailableInCodeJar: 'Non disponible dans CodeJar',
preview: 'Aperçu',
semicolons: 'Format : Utiliser des points-virgules',
Expand Down
3 changes: 3 additions & 0 deletions src/livecodes/i18n/locales/hi/translation.lokalise.json
Original file line number Diff line number Diff line change
Expand Up @@ -756,6 +756,9 @@
"editorSettings.lineNumbers": {
"translation": "पंक्ति संख्याएँ दिखाएँ"
},
"editorSettings.lineNumbersRelative": {
"translation": "सापेक्ष पंक्ति संख्या *"
},
"editorSettings.notAvailableInCodeJar": {
"translation": "CodeJar में उपलब्ध नहीं"
},
Expand Down
1 change: 1 addition & 0 deletions src/livecodes/i18n/locales/hi/translation.ts
Original file line number Diff line number Diff line change
Expand Up @@ -429,6 +429,7 @@ const translation: I18nTranslation = {
format: 'प्रारूप',
heading: 'संपादक सेटिंग्स',
lineNumbers: 'पंक्ति संख्याएँ दिखाएँ',
lineNumbersRelative: 'सापेक्ष पंक्ति संख्या *',
notAvailableInCodeJar: 'CodeJar में उपलब्ध नहीं',
preview: 'पूर्वावलोकन',
semicolons: 'प्रारूप: अर्धविराम का उपयोग करें',
Expand Down
3 changes: 3 additions & 0 deletions src/livecodes/i18n/locales/it/translation.lokalise.json
Original file line number Diff line number Diff line change
Expand Up @@ -756,6 +756,9 @@
"editorSettings.lineNumbers": {
"translation": "Mostra numeri di riga"
},
"editorSettings.lineNumbersRelative": {
"translation": "Numeri di riga relativi *"
},
"editorSettings.notAvailableInCodeJar": {
"translation": "Non disponibile in CodeJar"
},
Expand Down
Loading

0 comments on commit 73cb1f4

Please sign in to comment.