Skip to content

Commit e2717c1

Browse files
committed
Allow chose multiple editors
1 parent efcfc96 commit e2717c1

File tree

14 files changed

+175
-67
lines changed

14 files changed

+175
-67
lines changed

modules/context/repo.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -588,12 +588,12 @@ func RepoAssignment(ctx *Context) (cancel context.CancelFunc) {
588588
}
589589
ctx.Data["CloneButtonShowHTTPS"] = cloneButtonShowHTTPS
590590
ctx.Data["CloneButtonShowSSH"] = cloneButtonShowSSH
591-
editor, err := dev.GetUserDefaultEditorWithFallback(ctx.Doer)
591+
editors, err := dev.GetUserDefaultEditorsWithFallback(ctx.Doer)
592592
if err != nil {
593593
ctx.ServerError("dev.GetDefaultEditor", err)
594594
return
595595
}
596-
ctx.Data["CloneEditor"] = editor
596+
ctx.Data["CloneEditors"] = editors
597597
ctx.Data["CloneButtonOriginLink"] = ctx.Data["RepoCloneLink"] // it may be rewritten to the UncycloCloneLink by the router middleware
598598

599599
ctx.Data["RepoSearchEnabled"] = setting.Indexer.RepoIndexerEnabled

modules/util/slice.go

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,8 @@
33

44
package util
55

6+
import "strings"
7+
68
// RemoveIDFromList removes the given ID from the slice, if found.
79
// It does not preserve order, and assumes the ID is unique.
810
func RemoveIDFromList(list []int64, id int64) ([]int64, bool) {
@@ -15,3 +17,17 @@ func RemoveIDFromList(list []int64, id int64) ([]int64, bool) {
1517
}
1618
return list, false
1719
}
20+
21+
func SplitStringWithTrim(s, sep string) []string {
22+
if len(s) == 0 {
23+
return nil
24+
}
25+
var result []string
26+
for _, word := range strings.Split(s, sep) {
27+
word = strings.TrimSpace(word)
28+
if len(word) > 0 {
29+
result = append(result, word)
30+
}
31+
}
32+
return result
33+
}

options/locale/locale_en-US.ini

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2912,7 +2912,8 @@ config.get_setting_failed = Get setting %s failed
29122912
config.set_setting_failed = Set setting %s failed
29132913
29142914
config.dev_config = Development
2915-
config.dev_default_editor = Default Editor
2915+
config.dev_default_editors = Default Editors
2916+
config.dev_default_editors_desc = Chose default editors
29162917
29172918
monitor.cron = Cron Tasks
29182919
monitor.name = Name

public/img/svg/gitea-idea.svg

Lines changed: 1 addition & 0 deletions
Loading

routers/web/admin/config.go

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -194,16 +194,17 @@ func Config(ctx *context.Context) {
194194
return
195195
}
196196

197-
defaultEditorS := systemSettings.Get(dev.KeyDevDefaultEditor)
197+
defaultEditorS := systemSettings.Get(dev.KeyDevDefaultEditors)
198198
if defaultEditorS.SettingValue == "" {
199199
defaultEditorS = system_model.Setting{
200-
SettingKey: dev.KeyDevDefaultEditor,
201-
SettingValue: dev.DefaultEditorName(),
200+
SettingKey: dev.KeyDevDefaultEditors,
201+
SettingValue: dev.DefaultEditorsNames(),
202202
}
203203
}
204204

205205
ctx.Data["DevEditors"] = editors
206-
ctx.Data["DevDefaultEditor"] = dev.GetEditorByName(defaultEditorS.SettingValue)
206+
ctx.Data["DevDefaultEditorNames"] = defaultEditorS.SettingValue
207+
ctx.Data["DevDefaultEditorVersion"] = defaultEditorS.Version
207208

208209
ctx.HTML(http.StatusOK, tplConfig)
209210
}

routers/web/user/setting/profile.go

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -382,14 +382,22 @@ func Appearance(ctx *context.Context) {
382382
return
383383
}
384384

385-
myDefaultEditor, err := dev.GetUserDefaultEditorWithFallback(ctx.Doer)
385+
myDefaultEditors, err := dev.GetUserDefaultEditorsWithFallback(ctx.Doer)
386386
if err != nil {
387387
ctx.ServerError("dev.GetEditors", err)
388388
return
389389
}
390390

391+
var myEditorNames string
392+
for i, editor := range myDefaultEditors {
393+
if i > 0 {
394+
myEditorNames = myEditorNames + ","
395+
}
396+
myEditorNames = myEditorNames + editor.Name
397+
}
398+
391399
ctx.Data["DevEditors"] = editors
392-
ctx.Data["DevDefaultEditor"] = myDefaultEditor
400+
ctx.Data["DevDefaultEditorNames"] = myEditorNames
393401

394402
ctx.HTML(http.StatusOK, tplSettingsAppearance)
395403
}

routers/web/web.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1205,12 +1205,12 @@ func RegisterRoutes(m *web.Route) {
12051205
m.Get("/commit/{sha:[a-f0-9]{7,40}}.{ext:patch|diff}", repo.RawDiff)
12061206
}, repo.MustEnableUncyclo, func(ctx *context.Context) {
12071207
ctx.Data["PageIsUncyclo"] = true
1208-
editor, err := dev.GetUserDefaultEditorWithFallback(ctx.Doer)
1208+
editors, err := dev.GetUserDefaultEditorsWithFallback(ctx.Doer)
12091209
if err != nil {
12101210
ctx.ServerError("dev.GetDefaultEditor", err)
12111211
return
12121212
}
1213-
ctx.Data["CloneEditor"] = editor
1213+
ctx.Data["CloneEditors"] = editors
12141214
ctx.Data["CloneButtonOriginLink"] = ctx.Repo.Repository.UncycloCloneLink()
12151215
})
12161216

services/dev/editor.go

Lines changed: 50 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ import (
1212
"code.gitea.io/gitea/modules/log"
1313
)
1414

15-
const KeyDevDefaultEditor = "dev.default_editor"
15+
const KeyDevDefaultEditors = "dev.default_editors"
1616

1717
type Editor struct {
1818
Name string
@@ -35,6 +35,11 @@ var defaultEditors = []Editor{
3535
URL: "vscodium://vscode.git/clone?url=${repo_url}",
3636
Icon: `gitea-vscodium`,
3737
},
38+
{
39+
Name: "IDEA",
40+
URL: "jetbrains://idea/checkout/git?idea.required.plugins.id=Git4Idea&checkout.repo=${repo-url}",
41+
Icon: `gitea-idea`,
42+
},
3843
}
3944

4045
func GetEditorByName(name string) *Editor {
@@ -46,38 +51,48 @@ func GetEditorByName(name string) *Editor {
4651
return nil
4752
}
4853

54+
func GetEditorsByNames(names []string) []*Editor {
55+
editors := make([]*Editor, 0, len(names))
56+
for _, name := range names {
57+
if editor := GetEditorByName(name); editor != nil {
58+
editors = append(editors, editor)
59+
} else {
60+
log.Error("Unknown editor: %s", name)
61+
}
62+
}
63+
return editors
64+
}
65+
4966
// GetEditors returns all editors
5067
func GetEditors() ([]Editor, error) {
5168
return defaultEditors, nil
5269
}
5370

54-
func DefaultEditorName() string {
71+
func DefaultEditorsNames() string {
5572
return defaultEditors[0].Name
5673
}
5774

58-
func GetDefaultEditor() (*Editor, error) {
59-
defaultName, err := system.GetSetting(KeyDevDefaultEditor)
75+
func GetDefaultEditors() ([]*Editor, error) {
76+
defaultNames, err := system.GetSetting(KeyDevDefaultEditors)
6077
if err != nil && !system.IsErrSettingIsNotExist(err) {
6178
return nil, err
6279
}
63-
for _, editor := range defaultEditors {
64-
if editor.Name == defaultName {
65-
return &editor, nil
66-
}
67-
}
68-
return &defaultEditors[0], nil
80+
names := strings.Split(defaultNames, ",")
81+
return GetEditorsByNames(names), nil
6982
}
7083

71-
func SetDefaultEditor(name string) error {
72-
for _, editor := range defaultEditors {
73-
if editor.Name == name {
74-
return system.SetSetting(&system.Setting{
75-
SettingKey: KeyDevDefaultEditor,
76-
SettingValue: name,
77-
})
84+
func SetDefaultEditors(names []string) error {
85+
var validateNames []string
86+
for _, name := range names {
87+
if editor := GetEditorByName(name); editor != nil {
88+
validateNames = append(validateNames, name)
7889
}
7990
}
80-
return nil
91+
92+
return system.SetSetting(&system.Setting{
93+
SettingKey: KeyDevDefaultEditors,
94+
SettingValue: strings.Join(validateNames, ","),
95+
})
8196
}
8297

8398
type ErrUnknownEditor struct {
@@ -88,38 +103,40 @@ func (e ErrUnknownEditor) Error() string {
88103
return "Unknown editor: " + e.editorName
89104
}
90105

91-
func GetUserDefaultEditor(userID int64) (*Editor, error) {
92-
defaultName, err := user_model.GetSetting(userID, KeyDevDefaultEditor)
106+
func GetUserDefaultEditors(userID int64) ([]*Editor, error) {
107+
defaultNames, err := user_model.GetSetting(userID, KeyDevDefaultEditors)
93108
if err != nil {
94109
return nil, err
95110
}
96-
for _, editor := range defaultEditors {
97-
if editor.Name == defaultName {
98-
return &editor, nil
99-
}
100-
}
101-
return nil, ErrUnknownEditor{defaultName}
111+
names := strings.Split(defaultNames, ",")
112+
return GetEditorsByNames(names), nil
102113
}
103114

104-
func SetUserDefaultEditor(userID int64, name string) error {
105-
return user_model.SetUserSetting(userID, KeyDevDefaultEditor, name)
115+
func SetUserDefaultEditors(userID int64, names []string) error {
116+
var validateNames []string
117+
for _, name := range names {
118+
if editor := GetEditorByName(name); editor != nil {
119+
validateNames = append(validateNames, name)
120+
}
121+
}
122+
return user_model.SetUserSetting(userID, KeyDevDefaultEditors, strings.Join(validateNames, ","))
106123
}
107124

108-
func GetUserDefaultEditorWithFallback(user *user_model.User) (*Editor, error) {
125+
func GetUserDefaultEditorsWithFallback(user *user_model.User) ([]*Editor, error) {
109126
if user == nil || user.ID <= 0 {
110-
return GetDefaultEditor()
127+
return GetDefaultEditors()
111128
}
112-
editor, err := GetUserDefaultEditor(user.ID)
129+
editor, err := GetUserDefaultEditors(user.ID)
113130
if err == nil {
114131
return editor, nil
115132
}
116133

117134
if theErr, ok := err.(ErrUnknownEditor); ok {
118135
log.Error("Unknown editor for user %d: %s, fallback to system default", user.ID, theErr.editorName)
119-
return GetDefaultEditor()
136+
return GetDefaultEditors()
120137
}
121138
if user_model.IsErrUserSettingIsNotExist(err) {
122-
return GetDefaultEditor()
139+
return GetDefaultEditors()
123140
}
124141
return nil, err
125142
}

templates/admin/config.tmpl

Lines changed: 12 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -417,17 +417,18 @@
417417
<h4 class="ui top attached header">
418418
{{.locale.Tr "admin.config.dev_config"}}
419419
</h4>
420-
<div class="ui attached table segment">
421-
<dl class="dl-horizontal admin-dl-horizontal">
422-
<dt>{{$.locale.Tr "admin.config.dev_default_editor"}}</dt>
423-
<dd>
424-
<div class="ui floatting selection dropdown">
425-
<input type="hidden" name="dev.default_editor" version="{{$.DevDefaultEditorVersion}}">
420+
<div class="ui attached segment">
421+
<div class="ui list">
422+
<div class="item">
423+
{{$.locale.Tr "admin.config.dev_default_editors"}}
424+
</div>
425+
<div class="field">
426+
<div id="dev_editors_config" class="ui floating selection multiple dropdown">
427+
<input type="hidden" name="dev.default_editors" value="{{$.DevDefaultEditorNames}}" version="{{$.DevDefaultEditorVersion}}">
426428
<div class="default text">
427-
{{svg $.DevDefaultEditor.Icon 14}}
428-
{{$.DevDefaultEditor.Name}} - {{$.DevDefaultEditor.URL}}
429+
{{$.locale.Tr "admin.config.dev_default_editors_desc"}}
429430
</div>
430-
<div class="menu floatting">
431+
<div class="menu floating">
431432
{{range .DevEditors}}
432433
<div class="item" data-value="{{.Name}}">
433434
{{svg .Icon 14}}
@@ -436,8 +437,8 @@
436437
{{end}}
437438
</div>
438439
</div>
439-
</dd>
440-
</dl>
440+
</div>
441+
</div>
441442
</div>
442443
</div>
443444
</div>

templates/repo/clone_script.tmpl

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -23,8 +23,8 @@
2323
}
2424
for (const el of document.getElementsByClassName('js-clone-url-editor')) {
2525
let repo_url = encodeURIComponent(link);
26-
console.info(el, el.getAttribute('data-url'), repo_url);
27-
el['href'] = el.getAttribute('data-url');
26+
let data_url = decodeURI(el.getAttribute('data-url'))
27+
el['href'] = data_url.replaceAll('${repo_url}', repo_url);
2828
}
2929
})();
3030
</script>

templates/repo/home.tmpl

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -128,7 +128,9 @@
128128
<a class="item" id="cite-repo-button">{{svg "octicon-cross-reference" 16 "mr-3"}}{{.locale.Tr "repo.cite_this_repo"}}</a>
129129
{{end}}
130130
{{end}}
131-
<a class="item js-clone-url-editor" data-url="{{.CloneEditor.URL | SafeURL}}" href="{{.CloneEditor.RenderURL .CloneButtonOriginLink.HTTPS}}">{{svg .CloneEditor.Icon 16 "mr-3"}}{{.locale.Tr "repo.clone_in_editor" .CloneEditor.Name}}</a>
131+
{{range .CloneEditors}}
132+
<a class="item js-clone-url-editor" onerror="alert(1);" data-url="{{.URL | SafeURL}}" href="{{.RenderURL $.CloneButtonOriginLink.HTTPS}}">{{svg .Icon 16 "mr-3"}}{{$.locale.Tr "repo.clone_in_editor" .Name}}</a>
133+
{{end}}
132134
</div>
133135
</button>
134136
{{template "repo/clone_script" .}}{{/* the script will update `.js-clone-url` and related elements */}}

templates/user/settings/appearance.tmpl

Lines changed: 6 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -74,18 +74,17 @@
7474
{{.locale.Tr "admin.config.dev_config"}}
7575
</h4>
7676
<div class="ui attached segment">
77-
<div class="ui email list">
77+
<div class="ui list">
7878
<div class="item">
79-
{{$.locale.Tr "admin.config.dev_default_editor"}}
79+
{{$.locale.Tr "admin.config.dev_default_editors"}}
8080
</div>
8181
<div class="field">
82-
<div class="ui floatting selection dropdown">
83-
<input type="hidden" name="dev.default_editor" version="{{$.DevDefaultEditorVersion}}">
82+
<div class="ui floating selection dropdown multiple">
83+
<input type="hidden" name="dev.default_editors" value="{{$.DevDefaultEditorNames}}" version="{{$.DevDefaultEditorVersion}}">
8484
<div class="default text">
85-
{{svg $.DevDefaultEditor.Icon 14}}
86-
{{$.DevDefaultEditor.Name}} - {{$.DevDefaultEditor.URL}}
85+
{{$.locale.Tr "admin.config.dev_default_editors_desc"}}
8786
</div>
88-
<div class="menu floatting">
87+
<div class="menu floating">
8988
{{range .DevEditors}}
9089
<div class="item" data-value="{{.Name}}">
9190
{{svg .Icon 14}}

web_src/js/features/admin/config.js

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -39,14 +39,13 @@ export function initAdminConfigs() {
3939
onChange: (_text, _value, $choice) => {
4040
const $this = $choice.parent().parent();
4141
const input = $this.find('input');
42-
console.info($this, input);
4342
$.ajax({
4443
url: `${appSubUrl}/admin/config`,
4544
type: 'POST',
4645
data: {
4746
_csrf: csrfToken,
4847
key: input.attr('name'),
49-
value: input.attr('value'),
48+
value: _text,
5049
version: input.attr('version'),
5150
}
5251
}).done((resp) => {

0 commit comments

Comments
 (0)