Skip to content

Add ui.EDITOR_EOL, default to saving files with LF again #28119

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 10 commits into from
3 changes: 3 additions & 0 deletions custom/conf/app.example.ini
Original file line number Diff line number Diff line change
Expand Up @@ -1242,6 +1242,9 @@ LEVEL = Info
;; Change the sort type of the explore pages.
;; Default is "recentupdate", but you also have "alphabetically", "reverselastlogin", "newest", "oldest".
;EXPLORE_PAGING_DEFAULT_SORT = recentupdate
;;
;; Newline format for the web editor. Either "LF" or "CRLF". Can be overridden per-file with .editorconfig.
;EDITOR_EOL = LF

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
Expand Down
1 change: 1 addition & 0 deletions docs/content/administration/config-cheat-sheet.en-us.md
Original file line number Diff line number Diff line change
Expand Up @@ -232,6 +232,7 @@ The following configuration set `Content-Type: application/vnd.android.package-a
- `ONLY_SHOW_RELEVANT_REPOS`: **false**: Whether to only show relevant repos on the explore page when no keyword is specified and default sorting is used.
A repo is considered irrelevant if it's a fork or if it has no metadata (no description, no icon, no topic).
- `EXPLORE_PAGING_DEFAULT_SORT`: **recentupdate**: Change the sort type of the explore pages. Valid values are "recentupdate", "alphabetically", "reverselastlogin", "newest" and "oldest"
- `EDITOR_EOL`: **LF**: Newline format for the web editor. Either "LF" or "CRLF". Can be overridden per-file with .editorconfig.

### UI - Admin (`ui.admin`)

Expand Down
2 changes: 2 additions & 0 deletions modules/setting/ui.go
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ var UI = struct {
SearchRepoDescription bool
OnlyShowRelevantRepos bool
ExploreDefaultSort string `ini:"EXPLORE_PAGING_DEFAULT_SORT"`
EditorEol string `ini:"EDITOR_EOL"`
Copy link
Member Author

@silverwind silverwind Nov 19, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I guess this ini tag here is unnecessary because thiscase conversation is done implicitely, but I do like this expliciteness so that the name stays greppable.

By the way, where does this case conversation happen? It's not from the ini package, right?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think the correct Go name would even be EditorEOL


Notification struct {
MinTimeout time.Duration
Expand Down Expand Up @@ -82,6 +83,7 @@ var UI = struct {
Reactions: []string{`+1`, `-1`, `laugh`, `hooray`, `confused`, `heart`, `rocket`, `eyes`},
CustomEmojis: []string{`git`, `gitea`, `codeberg`, `gitlab`, `github`, `gogs`},
CustomEmojisMap: map[string]string{"git": ":git:", "gitea": ":gitea:", "codeberg": ":codeberg:", "gitlab": ":gitlab:", "github": ":github:", "gogs": ":gogs:"},
EditorEol: `LF`,
Notification: struct {
MinTimeout time.Duration
TimeoutStep time.Duration
Expand Down
3 changes: 3 additions & 0 deletions modules/templates/helper.go
Original file line number Diff line number Diff line change
Expand Up @@ -149,6 +149,9 @@ func NewFuncMap() template.FuncMap {
"MermaidMaxSourceCharacters": func() int {
return setting.MermaidMaxSourceCharacters
},
"EditorEol": func() string {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

See above

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

See above

return setting.UI.EditorEol
},

// -----------------------------------------------------------------
// render
Expand Down
16 changes: 15 additions & 1 deletion modules/util/string.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,11 @@

package util

import "github.com/yuin/goldmark/util"
import (
"strings"

"github.com/yuin/goldmark/util"
)

func isSnakeCaseUpper(c byte) bool {
return 'A' <= c && c <= 'Z'
Expand Down Expand Up @@ -85,3 +89,13 @@ func ToSnakeCase(input string) string {
}
return util.BytesToReadOnlyString(res)
}

// convert all newlines in string to \n
func ToLF(str string) string {
return strings.ReplaceAll(str, "\r", "")
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
return strings.ReplaceAll(str, "\r", "")
return strings.ReplaceAll(str, "\r\n", "\n")

}

// convert all newlines in string to \r\n
func ToCRLF(str string) string {
return strings.ReplaceAll(ToLF(str), "\n", "\r\n")
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
return strings.ReplaceAll(ToLF(str), "\n", "\r\n")
return strings.ReplaceAll(str, "(?:[^\r])\n", "\r\n")

}
8 changes: 8 additions & 0 deletions modules/util/string_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -45,3 +45,11 @@ func TestToSnakeCase(t *testing.T) {
assert.Equal(t, expected, ToSnakeCase(input))
}
}

func TestToLF(t *testing.T) {
assert.Equal(t, "\na\nbc\n\n", ToLF("\r\na\r\nb\rc\n\n"))
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
assert.Equal(t, "\na\nbc\n\n", ToLF("\r\na\r\nb\rc\n\n"))
assert.Equal(t, "\r\na\nbc\n\n", ToLF("\r\r\na\r\nb\rc\n\n"))

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Or how do we want to handle this case?
I can live both with the current approach of removing it completely, and my proposed approach of only converting \r\n -> \n

}

func TestToCRLF(t *testing.T) {
assert.Equal(t, "\r\na\r\nbc\r\n\r\n", ToCRLF("\r\na\r\nb\rc\n\n"))
}
18 changes: 17 additions & 1 deletion routers/web/repo/editor.go
Original file line number Diff line number Diff line change
Expand Up @@ -277,6 +277,22 @@ func editFilePost(ctx *context.Context, form forms.EditRepoFileForm, isNewFile b
operation = "create"
}

eol := setting.UI.EditorEol
ec, _, err := ctx.Repo.GetEditorconfig()
if err == nil {
def, err := ec.GetDefinitionForFilename(form.TreePath)
if err == nil {
eol = strings.ToUpper(def.EndOfLine)
}
}

content := form.Content
if eol == "CRLF" {
content = util.ToCRLF(content)
} else { // convert to LF, this was hardcoded before 1.21
content = util.ToLF(content)
}

if _, err := files_service.ChangeRepoFiles(ctx, ctx.Repo.Repository, ctx.Doer, &files_service.ChangeRepoFilesOptions{
LastCommitID: form.LastCommit,
OldBranch: ctx.Repo.BranchName,
Expand All @@ -287,7 +303,7 @@ func editFilePost(ctx *context.Context, form forms.EditRepoFileForm, isNewFile b
Operation: operation,
FromTreePath: ctx.Repo.TreePath,
TreePath: form.TreePath,
ContentReader: strings.NewReader(form.Content),
ContentReader: strings.NewReader(content),
},
},
Signoff: form.Signoff,
Expand Down
3 changes: 2 additions & 1 deletion templates/repo/editor/edit.tmpl
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,8 @@
data-context="{{.RepoLink}}"
data-previewable-extensions="{{.PreviewableExtensions}}"
data-line-wrap-extensions="{{.LineWrapExtensions}}"
data-initial-value="{{JsonUtils.EncodeToString .FileContent}}"></textarea>
data-initial-value="{{JsonUtils.EncodeToString .FileContent}}"
data-editor-eol="{{EditorEol}}"></textarea>
<div class="editor-loading is-loading"></div>
</div>
<div class="ui bottom attached tab segment markup" data-tab="preview">
Expand Down
7 changes: 4 additions & 3 deletions web_src/js/features/codeeditor.js
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ export async function createMonaco(textarea, filename, editorOpts) {
const monaco = await import(/* webpackChunkName: "monaco" */'monaco-editor');

initLanguages(monaco);
let {language, eol, ...other} = editorOpts;
let {language, eol: editorConfigEol, ...other} = editorOpts;
if (!language) language = getLanguage(filename);

const container = document.createElement('div');
Expand Down Expand Up @@ -121,8 +121,9 @@ export async function createMonaco(textarea, filename, editorOpts) {

const model = editor.getModel();

// Monaco performs auto-detection of dominant EOL in the file, biased towards LF for
// empty files. If there is an editorconfig value, override this detected value.
// Use eol format from editorconfig if present, otherwise fall back to ui.EDITOR_EOL
const editorEol = textarea.getAttribute('data-editor-eol');
const eol = editorConfigEol || editorEol || "LF";
if (eol in monaco.editor.EndOfLineSequence) {
model.setEOL(monaco.editor.EndOfLineSequence[eol]);
}
Expand Down