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:
@@ -319,7 +319,12 @@ func EditFile(ctx *context.Context) {
|
||||
}
|
||||
}
|
||||
|
||||
ctx.Data["CodeEditorConfig"] = getCodeEditorConfig(ctx, ctx.Repo.TreePath)
|
||||
editorConfig := getCodeEditorConfigByEditorconfig(ctx, ctx.Repo.TreePath)
|
||||
editorConfig.Autofocus = !isNewFile
|
||||
if isNewFile {
|
||||
editorConfig.Filename = ""
|
||||
}
|
||||
ctx.Data["CodeEditorConfig"] = editorConfig
|
||||
ctx.HTML(http.StatusOK, tplEditFile)
|
||||
}
|
||||
|
||||
|
||||
@@ -20,7 +20,7 @@ func NewDiffPatch(ctx *context.Context) {
|
||||
}
|
||||
|
||||
ctx.Data["PageIsPatch"] = true
|
||||
ctx.Data["CodeEditorConfig"] = CodeEditorConfig{} // not really editing a file, so no need to fill in the config
|
||||
ctx.Data["CodeEditorConfig"] = CodeEditorConfig{Filename: "diff.patch"}
|
||||
ctx.HTML(http.StatusOK, tplPatchFile)
|
||||
}
|
||||
|
||||
|
||||
@@ -65,27 +65,33 @@ func getClosestParentWithFiles(gitRepo *git.Repository, branchName, originTreePa
|
||||
return f(originTreePath, commit)
|
||||
}
|
||||
|
||||
// CodeEditorConfig is also used by frontend, defined in "codeeditor.ts"
|
||||
// CodeEditorConfig is also used by frontend, defined in "codeeditor" module
|
||||
type CodeEditorConfig struct {
|
||||
PreviewableExtensions []string `json:"previewable_extensions"`
|
||||
LineWrapExtensions []string `json:"line_wrap_extensions"`
|
||||
LineWrapOn bool `json:"line_wrap_on"`
|
||||
Filename string `json:"filename"` // the base name, not full path
|
||||
Autofocus bool `json:"autofocus"`
|
||||
PreviewableExtensions []string `json:"previewableExtensions,omitempty"`
|
||||
LineWrapExtensions []string `json:"lineWrapExtensions,omitempty"`
|
||||
LineWrap bool `json:"lineWrap"`
|
||||
Previewable bool `json:"previewable,omitempty"`
|
||||
|
||||
IndentStyle string `json:"indent_style"`
|
||||
IndentSize int `json:"indent_size"`
|
||||
TabWidth int `json:"tab_width"`
|
||||
TrimTrailingWhitespace *bool `json:"trim_trailing_whitespace,omitempty"`
|
||||
// the following can be read from .editorconfig if exists, or use default value
|
||||
IndentStyle string `json:"indentStyle"` // in most cases, keep it empty by default, detected by the source code
|
||||
IndentSize int `json:"indentSize"`
|
||||
TabWidth int `json:"tabWidth"`
|
||||
TrimTrailingWhitespace *bool `json:"trimTrailingWhitespace,omitempty"`
|
||||
}
|
||||
|
||||
func getCodeEditorConfig(ctx *context_service.Context, treePath string) (ret CodeEditorConfig) {
|
||||
func getCodeEditorConfigByEditorconfig(ctx *context_service.Context, treePath string) CodeEditorConfig {
|
||||
ret := CodeEditorConfig{Filename: path.Base(treePath)}
|
||||
ret.PreviewableExtensions = markup.PreviewableExtensions()
|
||||
ret.LineWrapExtensions = setting.Repository.Editor.LineWrapExtensions
|
||||
ret.LineWrapOn = util.SliceContainsString(ret.LineWrapExtensions, path.Ext(treePath), true)
|
||||
ret.LineWrap = util.SliceContainsString(ret.LineWrapExtensions, path.Ext(treePath), true)
|
||||
ret.Previewable = util.SliceContainsString(ret.PreviewableExtensions, path.Ext(treePath), true)
|
||||
ec, _, err := ctx.Repo.GetEditorconfig()
|
||||
if err == nil {
|
||||
def, err := ec.GetDefinitionForFilename(treePath)
|
||||
if err == nil {
|
||||
ret.IndentStyle = def.IndentStyle
|
||||
ret.IndentStyle = util.IfZero(def.IndentStyle, ret.IndentStyle)
|
||||
ret.IndentSize, _ = strconv.Atoi(def.IndentSize)
|
||||
ret.TabWidth = def.TabWidth
|
||||
ret.TrimTrailingWhitespace = def.TrimTrailingWhitespace
|
||||
|
||||
@@ -42,7 +42,7 @@ func GitHooksEdit(ctx *context.Context) {
|
||||
return
|
||||
}
|
||||
ctx.Data["Hook"] = hook
|
||||
ctx.Data["CodeEditorConfig"] = repo.CodeEditorConfig{} // not really editing a repo file, so no editor config
|
||||
ctx.Data["CodeEditorConfig"] = repo.CodeEditorConfig{Filename: name + ".sh", IndentStyle: "tab", TabWidth: 4}
|
||||
ctx.HTML(http.StatusOK, tplGithookEdit)
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user