Replace Monaco with CodeMirror (#36764)

- Replace monaco-editor with CodeMirror 6
- Add `--color-syntax-*` CSS variables for all syntax token types,
shared by CodeMirror, Chroma and EasyMDE
- Consolidate chroma CSS into a single theme-independent file
(`modules/chroma.css`)
- Syntax colors in the code editor now match the code view and
light/dark themes
- Code editor is now 12px instead of 14px font size to match code view
and GitHub
- Use a global style for kbd elements
- When editing existing files, focus will be on codemirror instead of
filename input.
- Keyboard shortcuts are roughtly the same as VSCode
- Add a "Find" button, useful for mobile
- Add context menu similar to Monaco
- Add a command palette (Ctrl/Cmd+Shift+P or F1) or via button
- Add clickable URLs via Ctrl/Cmd+click
- Add e2e test for the code editor
- Remove `window.codeEditors` global
- The main missing Monaco features are hover types and semantic rename
but these were not fully working because monaco operated only on single
files and only for JS/TS/HTML/CSS/JSON.

| | Monaco (main) | CodeMirror (cm) | Delta |
|---|---|---|---|
| **Build time** | 7.8s | 5.3s | **-32%** |
| **JS output** | 25 MB | 14 MB | **-44%** |
| **CSS output** | 1.2 MB | 1012 KB | **-17%** |
| **Total (no maps)** | 23.3 MB | 12.1 MB | **-48%** |

Fixes: #36311
Fixes: #14776
Fixes: #12171

<img width="1333" height="555" alt="image"
src="https://github.com/user-attachments/assets/f0fe3a28-1ed9-4f22-bf25-2b161501d7ce"
/>

---------

Signed-off-by: silverwind <me@silverwind.io>
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
Co-authored-by: wxiaoguang <wxiaoguang@gmail.com>
Co-authored-by: Giteabot <teabot@gitea.io>
Co-authored-by: Lunny Xiao <xiaolunwen@gmail.com>
This commit is contained in:
silverwind
2026-03-31 23:50:45 +02:00
committed by GitHub
parent 4747dd68bd
commit e2e8509239
48 changed files with 2590 additions and 766 deletions
+1 -1
View File
@@ -11,7 +11,7 @@
{{- end}}
</h3>
<div class="field">
<input name="commit_summary" maxlength="100" placeholder="{{if .PageIsDelete}}{{ctx.Locale.Tr "repo.editor.delete" .TreePath}}{{else if .PageIsUpload}}{{ctx.Locale.Tr "repo.editor.upload_files_to_dir" .TreePath}}{{else if .IsNewFile}}{{ctx.Locale.Tr "repo.editor.add_tmpl"}}{{else if .PageIsPatch}}{{ctx.Locale.Tr "repo.editor.patch"}}{{else}}{{ctx.Locale.Tr "repo.editor.update" .TreePath}}{{end}}" value="{{.commit_summary}}" autofocus>
<input name="commit_summary" maxlength="100" placeholder="{{if .PageIsDelete}}{{ctx.Locale.Tr "repo.editor.delete" .TreePath}}{{else if .PageIsUpload}}{{ctx.Locale.Tr "repo.editor.upload_files_to_dir" .TreePath}}{{else if .IsNewFile}}{{ctx.Locale.Tr "repo.editor.add_tmpl"}}{{else if .PageIsPatch}}{{ctx.Locale.Tr "repo.editor.patch"}}{{else}}{{ctx.Locale.Tr "repo.editor.update" .TreePath}}{{end}}" value="{{.commit_summary}}">
</div>
<div class="field">
<textarea name="commit_message" placeholder="{{ctx.Locale.Tr "repo.editor.commit_message_desc"}}" rows="5">{{.commit_message}}</textarea>
+1 -1
View File
@@ -5,7 +5,7 @@
{{range $i, $v := .TreeNames}}
<div class="breadcrumb-divider">/</div>
{{if eq $i $l}}
<input id="file-name" maxlength="255" value="{{$v}}" placeholder="{{ctx.Locale.Tr (Iif $.PageIsUpload "repo.editor.add_subdir" "repo.editor.name_your_file")}}" data-code-editor-config="{{JsonUtils.EncodeToString $.CodeEditorConfig}}" {{Iif $.PageIsUpload "" "required"}} autofocus>
<input id="file-name" maxlength="255" value="{{$v}}" placeholder="{{ctx.Locale.Tr (Iif $.PageIsUpload "repo.editor.add_subdir" "repo.editor.name_your_file")}}" {{Iif $.PageIsUpload "" "required"}}>
<span data-tooltip-content="{{ctx.Locale.Tr "repo.editor.filename_help"}}">{{svg "octicon-info"}}</span>
{{else}}
<span class="section"><a href="{{$.BranchLink}}/{{index $.TreePaths $i | PathEscapeSegments}}">{{$v}}</a></span>
+3 -3
View File
@@ -21,7 +21,7 @@
<div class="flex-text-block tw-justify-between tw-flex-wrap">
<div class="ui compact small menu small-menu-items repo-editor-menu tw-self-start">
<a class="active item" data-tab="write">{{svg "octicon-code"}} {{if .IsNewFile}}{{ctx.Locale.Tr "repo.editor.new_file"}}{{else}}{{ctx.Locale.Tr "repo.editor.edit_file"}}{{end}}</a>
<a class="item" data-tab="preview" data-preview-url="{{.Repository.Link}}/markup" data-preview-context-ref="{{.RepoLink}}/src/{{.RefTypeNameSubURL}}">{{svg "octicon-eye"}} {{ctx.Locale.Tr "preview"}}</a>
<a class="item{{if not .CodeEditorConfig.Previewable}} tw-hidden{{end}}" data-tab="preview" data-preview-url="{{.Repository.Link}}/markup" data-preview-context-ref="{{.RepoLink}}/src/{{.RefTypeNameSubURL}}">{{svg "octicon-eye"}} {{ctx.Locale.Tr "preview"}}</a>
{{if not .IsNewFile}}
<a class="item" data-tab="diff" hx-params="context,content" hx-vals='{"context":"{{.BranchLink}}"}' hx-include="#edit_area" hx-swap="innerHTML" hx-target=".tab[data-tab='diff']" hx-indicator=".tab[data-tab='diff']" hx-post="{{.RepoLink}}/_preview/{{.BranchName | PathEscapeSegments}}/{{.TreePath | PathEscapeSegments}}">{{svg "octicon-diff"}} {{ctx.Locale.Tr "repo.editor.preview_changes"}}</a>
{{end}}
@@ -32,8 +32,8 @@
<div class="ui bottom attached segment tw-p-0">
<div class="ui active tab tw-rounded-b" data-tab="write">
<textarea id="edit_area" name="content" class="tw-hidden" data-id="repo-{{.Repository.Name}}-{{.TreePath}}"
data-previewable-extensions="{{StringUtils.Join $.CodeEditorConfig.PreviewableExtensions ","}}"
data-line-wrap-extensions="{{StringUtils.Join $.CodeEditorConfig.LineWrapExtensions ","}}">{{.FileContent}}</textarea>
data-code-editor-config="{{JsonUtils.EncodeToString $.CodeEditorConfig}}"
placeholder="{{ctx.Locale.Tr "editor.code_editor.placeholder"}}">{{.FileContent}}</textarea>
<div class="editor-loading is-loading"></div>
</div>
<div class="ui tab tw-px-4 tw-py-3" data-tab="preview">
+5 -3
View File
@@ -1,7 +1,9 @@
{{$indentStyle := $.CodeEditorConfig.IndentStyle}}
{{$indentSize := or $.CodeEditorConfig.IndentSize 4}}
{{$lineWrapOn := $.CodeEditorConfig.LineWrapOn}}
{{$lineWrap := $.CodeEditorConfig.LineWrap}}
<div class="flex-text-block code-editor-options">
<button type="button" class="js-code-find ui compact mini icon button" aria-label="{{ctx.Locale.Tr "editor.code_editor.find"}}">{{svg "octicon-search"}}</button>
<button type="button" class="js-code-command-palette ui compact mini icon button" aria-label="{{ctx.Locale.Tr "editor.code_editor.command_palette"}}">{{svg "octicon-command-palette"}}</button>
<div class="native-select">
<select class="js-indent-style-select" aria-label="{{ctx.Locale.Tr "text_indent_style"}}">
<optgroup label="{{ctx.Locale.Tr "text_indent_style"}}">
@@ -22,8 +24,8 @@
<div class="native-select">
<select class="js-line-wrap-select" aria-label="{{ctx.Locale.Tr "text_line_wrap_mode"}}">
<optgroup label="{{ctx.Locale.Tr "text_line_wrap_mode"}}">
<option{{if $lineWrapOn}} selected{{end}} value="on">{{ctx.Locale.Tr "text_line_wrap"}}</option>
<option{{if not $lineWrapOn}} selected{{end}} value="off">{{ctx.Locale.Tr "text_line_nowrap"}}</option>
<option{{if $lineWrap}} selected{{end}} value="on">{{ctx.Locale.Tr "text_line_wrap"}}</option>
<option{{if not $lineWrap}} selected{{end}} value="off">{{ctx.Locale.Tr "text_line_nowrap"}}</option>
</optgroup>
</select>
</div>
+3 -1
View File
@@ -31,7 +31,9 @@
<div class="ui bottom attached segment tw-p-0">
<div class="ui active tab tw-rounded-b" data-tab="write">
<textarea id="edit_area" name="content" class="tw-hidden" data-id="repo-{{.Repository.Name}}-patch"
data-context="{{.RepoLink}}">{{.FileContent}}</textarea>
data-code-editor-config="{{JsonUtils.EncodeToString $.CodeEditorConfig}}"
data-context="{{.RepoLink}}"
placeholder="{{ctx.Locale.Tr "editor.code_editor.placeholder"}}">{{.FileContent}}</textarea>
<div class="editor-loading is-loading"></div>
</div>
</div>
+4 -7
View File
@@ -2,7 +2,7 @@
<div class="repo-setting-content">
<form class="ui form" action="{{.Link}}" method="post">
<h4 class="ui top attached header flex-text-block tw-justify-between tw-flex-wrap">
{{ctx.Locale.Tr "repo.settings.githooks"}}
{{.Hook.Name}}
<div class="tw-font-normal tw-font-sans tw-text-base">
{{template "repo/editor/options" dict "CodeEditorConfig" $.CodeEditorConfig}}
</div>
@@ -10,13 +10,10 @@
<div class="ui attached segment">
<p>{{ctx.Locale.Tr "repo.settings.githook_edit_desc"}}</p>
{{with .Hook}}
<div class="inline field">
<label>{{ctx.Locale.Tr "repo.settings.githook_name"}}</label>
<span class="hook-filename">{{.Name}}</span>
</div>
<div class="field">
<label for="content">{{ctx.Locale.Tr "repo.settings.githook_content"}}</label>
<textarea id="content" name="content" class="tw-hidden">{{if .IsActive}}{{.Content}}{{else}}{{.Sample}}{{end}}</textarea>
<textarea id="content" name="content" class="tw-hidden"
data-code-editor-config="{{JsonUtils.EncodeToString $.CodeEditorConfig}}"
placeholder="{{ctx.Locale.Tr "editor.code_editor.placeholder"}}">{{if .IsActive}}{{.Content}}{{else}}{{.Sample}}{{end}}</textarea>
<div class="editor-loading is-loading"></div>
</div>
<div class="inline field">