From 1b3a46dd3612c7a9db52e0bf5f583253b21d28f5 Mon Sep 17 00:00:00 2001 From: silverwind Date: Wed, 29 Jan 2025 20:06:52 +0100 Subject: [PATCH 01/10] Add editor settings UI to code editor Related to: https://github.com/go-gitea/gitea/issues/9071 --- modules/templates/helper.go | 2 ++ options/locale/locale_en-US.ini | 8 ++++++++ routers/web/repo/cherry_pick.go | 4 ++-- routers/web/repo/editor.go | 22 +++++++++++++++------- routers/web/repo/patch.go | 4 ++-- templates/repo/editor/edit.tmpl | 19 ++++++++++++------- templates/repo/editor/options.tmpl | 20 ++++++++++++++++++++ templates/repo/editor/patch.tmpl | 2 +- web_src/js/features/codeeditor.ts | 23 +++++++++++++++++------ 9 files changed, 79 insertions(+), 25 deletions(-) create mode 100644 templates/repo/editor/options.tmpl diff --git a/modules/templates/helper.go b/modules/templates/helper.go index a2cc166de9755..a63e4dfa0ca5b 100644 --- a/modules/templates/helper.go +++ b/modules/templates/helper.go @@ -9,6 +9,7 @@ import ( "html" "html/template" "net/url" + "path" "strings" "time" @@ -49,6 +50,7 @@ func NewFuncMap() template.FuncMap { "PathEscape": url.PathEscape, "PathEscapeSegments": util.PathEscapeSegments, + "PathExt": path.Ext, // utils "StringUtils": NewStringUtils, diff --git a/options/locale/locale_en-US.ini b/options/locale/locale_en-US.ini index 85d2c71ec7181..ccadc4cca16a2 100644 --- a/options/locale/locale_en-US.ini +++ b/options/locale/locale_en-US.ini @@ -163,6 +163,14 @@ filter.private = Private no_results_found = No results found. internal_error_skipped = Internal error occurred but is skipped: %s +characters_spaces = Spaces +characters_tabs = Tabs +text_indent_style = Indent Stype +text_indent_size = Indent Size +text_line_wrap = Wrap +text_line_nowrap = No wrap +text_line_wrap_mode = Line wrap mode + [search] search = Search... type_tooltip = Search type diff --git a/routers/web/repo/cherry_pick.go b/routers/web/repo/cherry_pick.go index 33d941c9d886c..e2f0271d703eb 100644 --- a/routers/web/repo/cherry_pick.go +++ b/routers/web/repo/cherry_pick.go @@ -56,7 +56,7 @@ func CherryPick(ctx *context.Context) { } ctx.Data["new_branch_name"] = GetUniquePatchBranchName(ctx) ctx.Data["last_commit"] = ctx.Repo.CommitID - ctx.Data["LineWrapExtensions"] = strings.Join(setting.Repository.Editor.LineWrapExtensions, ",") + ctx.Data["LineWrapExtensions"] = setting.Repository.Editor.LineWrapExtensions ctx.Data["BranchLink"] = ctx.Repo.RepoLink + "/src/" + ctx.Repo.RefTypeNameSubURL() ctx.HTML(200, tplCherryPick) @@ -84,7 +84,7 @@ func CherryPickPost(ctx *context.Context) { ctx.Data["commit_choice"] = form.CommitChoice ctx.Data["new_branch_name"] = form.NewBranchName ctx.Data["last_commit"] = ctx.Repo.CommitID - ctx.Data["LineWrapExtensions"] = strings.Join(setting.Repository.Editor.LineWrapExtensions, ",") + ctx.Data["LineWrapExtensions"] = setting.Repository.Editor.LineWrapExtensions ctx.Data["BranchLink"] = ctx.Repo.RepoLink + "/src/" + ctx.Repo.RefTypeNameSubURL() if ctx.HasError() { diff --git a/routers/web/repo/editor.go b/routers/web/repo/editor.go index 85f407ab8d795..28946016b9bb3 100644 --- a/routers/web/repo/editor.go +++ b/routers/web/repo/editor.go @@ -28,6 +28,8 @@ import ( "code.gitea.io/gitea/services/context/upload" "code.gitea.io/gitea/services/forms" files_service "code.gitea.io/gitea/services/repository/files" + + "github.com/editorconfig/editorconfig-core-go/v2" ) const ( @@ -191,8 +193,13 @@ func editFile(ctx *context.Context, isNewFile bool) { ctx.Data["new_branch_name"] = GetUniquePatchBranchName(ctx) ctx.Data["last_commit"] = ctx.Repo.CommitID ctx.Data["PreviewableExtensions"] = strings.Join(markup.PreviewableExtensions(), ",") - ctx.Data["LineWrapExtensions"] = strings.Join(setting.Repository.Editor.LineWrapExtensions, ",") - ctx.Data["EditorconfigJson"] = GetEditorConfig(ctx, treePath) + ctx.Data["LineWrapExtensions"] = setting.Repository.Editor.LineWrapExtensions + + ecDef := GetEditorConfig(ctx, treePath) + ecBytes, _ := json.Marshal(ecDef) + ctx.Data["EditorconfigJson"] = string(ecBytes) + ctx.Data["EditorconfigIndentStyle"] = ecDef.IndentStyle + ctx.Data["EditorconfigIndentSize"] = ecDef.IndentSize ctx.Data["IsEditingFileOnly"] = ctx.FormString("return_uri") != "" ctx.Data["ReturnURI"] = ctx.FormString("return_uri") @@ -201,16 +208,17 @@ func editFile(ctx *context.Context, isNewFile bool) { } // GetEditorConfig returns a editorconfig JSON string for given treePath or "null" -func GetEditorConfig(ctx *context.Context, treePath string) string { +func GetEditorConfig(ctx *context.Context, treePath string) *editorconfig.Definition { ec, _, err := ctx.Repo.GetEditorconfig() if err == nil { def, err := ec.GetDefinitionForFilename(treePath) if err == nil { - jsonStr, _ := json.Marshal(def) - return string(jsonStr) + return def + } else { + return nil } } - return "null" + return nil } // EditFile render edit file page @@ -245,7 +253,7 @@ func editFilePost(ctx *context.Context, form forms.EditRepoFileForm, isNewFile b ctx.Data["new_branch_name"] = form.NewBranchName ctx.Data["last_commit"] = ctx.Repo.CommitID ctx.Data["PreviewableExtensions"] = strings.Join(markup.PreviewableExtensions(), ",") - ctx.Data["LineWrapExtensions"] = strings.Join(setting.Repository.Editor.LineWrapExtensions, ",") + ctx.Data["LineWrapExtensions"] = setting.Repository.Editor.LineWrapExtensions ctx.Data["EditorconfigJson"] = GetEditorConfig(ctx, form.TreePath) if ctx.HasError() { diff --git a/routers/web/repo/patch.go b/routers/web/repo/patch.go index 4d47a705d6e94..520451ed97427 100644 --- a/routers/web/repo/patch.go +++ b/routers/web/repo/patch.go @@ -36,7 +36,7 @@ func NewDiffPatch(ctx *context.Context) { } ctx.Data["new_branch_name"] = GetUniquePatchBranchName(ctx) ctx.Data["last_commit"] = ctx.Repo.CommitID - ctx.Data["LineWrapExtensions"] = strings.Join(setting.Repository.Editor.LineWrapExtensions, ",") + ctx.Data["LineWrapExtensions"] = setting.Repository.Editor.LineWrapExtensions ctx.Data["BranchLink"] = ctx.Repo.RepoLink + "/src/" + ctx.Repo.RefTypeNameSubURL() ctx.HTML(200, tplPatchFile) @@ -59,7 +59,7 @@ func NewDiffPatchPost(ctx *context.Context) { ctx.Data["commit_choice"] = form.CommitChoice ctx.Data["new_branch_name"] = form.NewBranchName ctx.Data["last_commit"] = ctx.Repo.CommitID - ctx.Data["LineWrapExtensions"] = strings.Join(setting.Repository.Editor.LineWrapExtensions, ",") + ctx.Data["LineWrapExtensions"] = setting.Repository.Editor.LineWrapExtensions if ctx.HasError() { ctx.HTML(200, tplPatchFile) diff --git a/templates/repo/editor/edit.tmpl b/templates/repo/editor/edit.tmpl index 577a2be9ad38e..9fcbb5d78bf79 100644 --- a/templates/repo/editor/edit.tmpl +++ b/templates/repo/editor/edit.tmpl @@ -30,19 +30,24 @@
-
+ data-line-wrap-extensions="{{StringUtils.Join .LineWrapExtensions ","}}">{{.FileContent}}
diff --git a/templates/repo/editor/options.tmpl b/templates/repo/editor/options.tmpl new file mode 100644 index 0000000000000..6a48a9bdfc164 --- /dev/null +++ b/templates/repo/editor/options.tmpl @@ -0,0 +1,20 @@ + + +{{$mode := (Iif (SliceUtils.Contains .LineWrapExtensions (PathExt .TreePath)) "on" "off")}} + diff --git a/templates/repo/editor/patch.tmpl b/templates/repo/editor/patch.tmpl index 33a7c2a89d8c7..ce17d1b714e58 100644 --- a/templates/repo/editor/patch.tmpl +++ b/templates/repo/editor/patch.tmpl @@ -28,7 +28,7 @@
diff --git a/web_src/js/features/codeeditor.ts b/web_src/js/features/codeeditor.ts index af9830a4db232..48144281ed32b 100644 --- a/web_src/js/features/codeeditor.ts +++ b/web_src/js/features/codeeditor.ts @@ -38,6 +38,7 @@ const baseOptions: MonacoOpts = { scrollbar: {horizontalScrollbarSize: 6, verticalScrollbarSize: 6}, scrollBeyondLastLine: false, automaticLayout: true, + indentSize: 'tabSize', }; function getEditorconfig(input: HTMLInputElement): EditorConfig | null { @@ -163,6 +164,20 @@ export async function createMonaco(textarea: HTMLTextAreaElement, filename: stri textarea.dispatchEvent(new Event('change')); // seems to be needed for jquery-are-you-sure }); + const form = textarea.closest('form'); + form.querySelector('.js-indent-style-select').addEventListener('change', (e) => { + const insertSpaces = (e.target as HTMLSelectElement).value === 'space'; + editor.updateOptions({insertSpaces, useTabStops: !insertSpaces}); + }); + form.querySelector('.js-indent-size-select').addEventListener('change', (e) => { + const tabSize = Number((e.target as HTMLSelectElement).value); + editor.updateOptions({tabSize}); + }); + form.querySelector('.js-line-wrap-select').addEventListener('change', (e) => { + const wordWrap = (e.target as HTMLSelectElement).value as IEditorOptions['wordWrap']; + editor.updateOptions({wordWrap}); + }); + exportEditor(editor); const loading = document.querySelector('.editor-loading'); @@ -225,12 +240,8 @@ function getEditorConfigOptions(ec: EditorConfig | null): MonacoOpts { const opts: MonacoOpts = {}; opts.detectIndentation = !('indent_style' in ec) || !('indent_size' in ec); - if ('indent_size' in ec) { - opts.indentSize = Number(ec.indent_size); - } - if ('tab_width' in ec) { - opts.tabSize = Number(ec.tab_width) || Number(ec.indent_size); - } + opts.tabSize = Number(ec.tab_width) || Number(ec.indent_size) || 4; + if ('max_line_length' in ec) { opts.rulers = [Number(ec.max_line_length)]; } From f5346fbadd5dd832d1321e4d5ed12cb9f53462e5 Mon Sep 17 00:00:00 2001 From: silverwind Date: Wed, 29 Jan 2025 20:12:25 +0100 Subject: [PATCH 02/10] fix locale --- options/locale/locale_en-US.ini | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/options/locale/locale_en-US.ini b/options/locale/locale_en-US.ini index ccadc4cca16a2..d80be1a244c53 100644 --- a/options/locale/locale_en-US.ini +++ b/options/locale/locale_en-US.ini @@ -165,8 +165,8 @@ internal_error_skipped = Internal error occurred but is skipped: %s characters_spaces = Spaces characters_tabs = Tabs -text_indent_style = Indent Stype -text_indent_size = Indent Size +text_indent_style = Indent style +text_indent_size = Indent size text_line_wrap = Wrap text_line_nowrap = No wrap text_line_wrap_mode = Line wrap mode From 820d96480d5dbbc7ea51a264efa1d084288ba76b Mon Sep 17 00:00:00 2001 From: silverwind Date: Wed, 29 Jan 2025 20:18:11 +0100 Subject: [PATCH 03/10] use StringUtils.Join for PreviewableExtensions too --- routers/web/repo/editor.go | 4 ++-- templates/repo/editor/edit.tmpl | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/routers/web/repo/editor.go b/routers/web/repo/editor.go index 28946016b9bb3..ce0b7a47c8933 100644 --- a/routers/web/repo/editor.go +++ b/routers/web/repo/editor.go @@ -192,7 +192,7 @@ func editFile(ctx *context.Context, isNewFile bool) { } ctx.Data["new_branch_name"] = GetUniquePatchBranchName(ctx) ctx.Data["last_commit"] = ctx.Repo.CommitID - ctx.Data["PreviewableExtensions"] = strings.Join(markup.PreviewableExtensions(), ",") + ctx.Data["PreviewableExtensions"] = markup.PreviewableExtensions() ctx.Data["LineWrapExtensions"] = setting.Repository.Editor.LineWrapExtensions ecDef := GetEditorConfig(ctx, treePath) @@ -252,7 +252,7 @@ func editFilePost(ctx *context.Context, form forms.EditRepoFileForm, isNewFile b ctx.Data["commit_choice"] = form.CommitChoice ctx.Data["new_branch_name"] = form.NewBranchName ctx.Data["last_commit"] = ctx.Repo.CommitID - ctx.Data["PreviewableExtensions"] = strings.Join(markup.PreviewableExtensions(), ",") + ctx.Data["PreviewableExtensions"] = markup.PreviewableExtensions() ctx.Data["LineWrapExtensions"] = setting.Repository.Editor.LineWrapExtensions ctx.Data["EditorconfigJson"] = GetEditorConfig(ctx, form.TreePath) diff --git a/templates/repo/editor/edit.tmpl b/templates/repo/editor/edit.tmpl index 9fcbb5d78bf79..bafe77b4adbbc 100644 --- a/templates/repo/editor/edit.tmpl +++ b/templates/repo/editor/edit.tmpl @@ -46,7 +46,7 @@
From cc5666966ab46bb52e6f2585cf68911930434809 Mon Sep 17 00:00:00 2001 From: silverwind Date: Wed, 29 Jan 2025 20:32:40 +0100 Subject: [PATCH 04/10] fix lint --- routers/web/repo/editor.go | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/routers/web/repo/editor.go b/routers/web/repo/editor.go index ce0b7a47c8933..9a065d22d0e04 100644 --- a/routers/web/repo/editor.go +++ b/routers/web/repo/editor.go @@ -214,9 +214,8 @@ func GetEditorConfig(ctx *context.Context, treePath string) *editorconfig.Defini def, err := ec.GetDefinitionForFilename(treePath) if err == nil { return def - } else { - return nil } + return nil } return nil } From b76d014297da5c51d97fe4f139bb288bed17319e Mon Sep 17 00:00:00 2001 From: silverwind Date: Wed, 29 Jan 2025 20:39:13 +0100 Subject: [PATCH 05/10] prefer indent_size --- web_src/js/features/codeeditor.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/web_src/js/features/codeeditor.ts b/web_src/js/features/codeeditor.ts index 48144281ed32b..0e57c632fc22a 100644 --- a/web_src/js/features/codeeditor.ts +++ b/web_src/js/features/codeeditor.ts @@ -240,7 +240,7 @@ function getEditorConfigOptions(ec: EditorConfig | null): MonacoOpts { const opts: MonacoOpts = {}; opts.detectIndentation = !('indent_style' in ec) || !('indent_size' in ec); - opts.tabSize = Number(ec.tab_width) || Number(ec.indent_size) || 4; + opts.tabSize = Number(ec.indent_size) || Number(ec.tab_width) || 4; if ('max_line_length' in ec) { opts.rulers = [Number(ec.max_line_length)]; From f9ac1e0642d4a3e5559673d0ad7bfc5c3ce236cf Mon Sep 17 00:00:00 2001 From: silverwind Date: Wed, 29 Jan 2025 20:40:10 +0100 Subject: [PATCH 06/10] add comment --- web_src/js/features/codeeditor.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/web_src/js/features/codeeditor.ts b/web_src/js/features/codeeditor.ts index 0e57c632fc22a..f217bab8af448 100644 --- a/web_src/js/features/codeeditor.ts +++ b/web_src/js/features/codeeditor.ts @@ -240,6 +240,7 @@ function getEditorConfigOptions(ec: EditorConfig | null): MonacoOpts { const opts: MonacoOpts = {}; opts.detectIndentation = !('indent_style' in ec) || !('indent_size' in ec); + // we use indentSize='tabSize' so these numbers always match opts.tabSize = Number(ec.indent_size) || Number(ec.tab_width) || 4; if ('max_line_length' in ec) { From 1e1175aaec31d8142a71faedff548f32ae6aa713 Mon Sep 17 00:00:00 2001 From: silverwind Date: Wed, 29 Jan 2025 20:41:48 +0100 Subject: [PATCH 07/10] default wordWrap --- web_src/js/features/codeeditor.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/web_src/js/features/codeeditor.ts b/web_src/js/features/codeeditor.ts index f217bab8af448..0b385397a1022 100644 --- a/web_src/js/features/codeeditor.ts +++ b/web_src/js/features/codeeditor.ts @@ -39,6 +39,7 @@ const baseOptions: MonacoOpts = { scrollBeyondLastLine: false, automaticLayout: true, indentSize: 'tabSize', + wordWrap: 'on', }; function getEditorconfig(input: HTMLInputElement): EditorConfig | null { From 6a5974ed360a79b5df402506cde3208624ca2924 Mon Sep 17 00:00:00 2001 From: silverwind Date: Wed, 29 Jan 2025 21:27:23 +0100 Subject: [PATCH 08/10] Revert "default wordWrap" This reverts commit 1e1175aaec31d8142a71faedff548f32ae6aa713. --- web_src/js/features/codeeditor.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/web_src/js/features/codeeditor.ts b/web_src/js/features/codeeditor.ts index 0b385397a1022..f217bab8af448 100644 --- a/web_src/js/features/codeeditor.ts +++ b/web_src/js/features/codeeditor.ts @@ -39,7 +39,6 @@ const baseOptions: MonacoOpts = { scrollBeyondLastLine: false, automaticLayout: true, indentSize: 'tabSize', - wordWrap: 'on', }; function getEditorconfig(input: HTMLInputElement): EditorConfig | null { From ff9f78c12c2ea9adde69f2a89ff88d0ecc197b3a Mon Sep 17 00:00:00 2001 From: silverwind Date: Wed, 7 May 2025 11:56:17 +0200 Subject: [PATCH 09/10] Update routers/web/repo/editor.go --- routers/web/repo/editor.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/routers/web/repo/editor.go b/routers/web/repo/editor.go index 9a065d22d0e04..05613341af686 100644 --- a/routers/web/repo/editor.go +++ b/routers/web/repo/editor.go @@ -207,7 +207,7 @@ func editFile(ctx *context.Context, isNewFile bool) { ctx.HTML(http.StatusOK, tplEditFile) } -// GetEditorConfig returns a editorconfig JSON string for given treePath or "null" +// GetEditorConfig returns a editorconfig JSON string for given treePath or nil func GetEditorConfig(ctx *context.Context, treePath string) *editorconfig.Definition { ec, _, err := ctx.Repo.GetEditorconfig() if err == nil { From f7d8031872fd2abbfc5ed00b64363caf0fd84b44 Mon Sep 17 00:00:00 2001 From: silverwind Date: Wed, 7 May 2025 11:56:59 +0200 Subject: [PATCH 10/10] Update routers/web/repo/editor.go --- routers/web/repo/editor.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/routers/web/repo/editor.go b/routers/web/repo/editor.go index 05613341af686..420f50ee43cc0 100644 --- a/routers/web/repo/editor.go +++ b/routers/web/repo/editor.go @@ -207,7 +207,7 @@ func editFile(ctx *context.Context, isNewFile bool) { ctx.HTML(http.StatusOK, tplEditFile) } -// GetEditorConfig returns a editorconfig JSON string for given treePath or nil +// GetEditorConfig returns the editorconfig definition for given treePath or nil func GetEditorConfig(ctx *context.Context, treePath string) *editorconfig.Definition { ec, _, err := ctx.Repo.GetEditorconfig() if err == nil {