Skip to content

Commit ed2cc6b

Browse files
committed
Fix Cursor patch to be more consistent
1 parent 3c286ce commit ed2cc6b

File tree

1 file changed

+151
-23
lines changed

1 file changed

+151
-23
lines changed

patches/0018-BLENDER-Add-Line-Length-indicator-for-cursor.patch

Lines changed: 151 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -1,29 +1,95 @@
1-
From b16e4d99ebb8519b4d8abf5a1d7b4beb3356aa59 Mon Sep 17 00:00:00 2001
1+
From 0a5d6eeb66cbece3a1df154d126536dfab28b324 Mon Sep 17 00:00:00 2001
22
From: Bart van der Braak <bart@blender.org>
33
Date: Wed, 30 Apr 2025 18:09:40 +0200
4-
Subject: [PATCH 18/18] BLENDER: Add Line Length indicator for cursor
4+
Subject: [PATCH] BLENDER: Add Line Length indicator for cursor
55

66
---
7-
.../js/components/PullRequestMergeForm.vue | 31 ++++++++++++++++++-
8-
.../js/features/comp/ComboMarkdownEditor.ts | 21 +++++++++++++
9-
2 files changed, 51 insertions(+), 1 deletion(-)
7+
templates/repo/editor/commit_form.tmpl | 52 ++++++++++++++++++
8+
.../js/components/PullRequestMergeForm.vue | 40 +++++++++++++-
9+
.../js/features/comp/ComboMarkdownEditor.ts | 54 +++++++++++++++++--
10+
3 files changed, 142 insertions(+), 4 deletions(-)
1011

12+
diff --git a/templates/repo/editor/commit_form.tmpl b/templates/repo/editor/commit_form.tmpl
13+
index c050324e93..2bb9395645 100644
14+
--- a/templates/repo/editor/commit_form.tmpl
15+
+++ b/templates/repo/editor/commit_form.tmpl
16+
@@ -13,6 +13,58 @@
17+
</div>
18+
<div class="field">
19+
<textarea name="commit_message" placeholder="{{ctx.Locale.Tr "repo.editor.commit_message_desc"}}" rows="5">{{.commit_message}}</textarea>
20+
+ <script>
21+
+ (function () {
22+
+ const textarea = document.querySelector('.commit-form textarea[name="commit_message"]');
23+
+ if (!textarea) return;
24+
+
25+
+ const statusbar = document.createElement('div');
26+
+ statusbar.className = 'editor-statusbar';
27+
+
28+
+ const autosave = document.createElement('span');
29+
+ autosave.className = 'autosave';
30+
+
31+
+ const lines = document.createElement('span');
32+
+ lines.className = 'lines';
33+
+ lines.textContent = '1';
34+
+
35+
+ const words = document.createElement('span');
36+
+ words.className = 'words';
37+
+ words.textContent = '1';
38+
+
39+
+ const cursor = document.createElement('span');
40+
+ cursor.className = 'cursor';
41+
+ cursor.textContent = '1:1';
42+
+
43+
+ statusbar.appendChild(autosave);
44+
+ statusbar.appendChild(lines);
45+
+ statusbar.appendChild(words);
46+
+ statusbar.appendChild(cursor);
47+
+ textarea.parentElement.appendChild(statusbar);
48+
+
49+
+ function updateStatus() {
50+
+ const value = textarea.value;
51+
+ const pos = textarea.selectionStart;
52+
+
53+
+ const linesArray = value.substr(0, pos).split('\n');
54+
+ const line = linesArray.length;
55+
+ const column = linesArray[linesArray.length - 1].length + 1;
56+
+
57+
+ const totalLines = value.split('\n').length;
58+
+ const totalWords = (value.match(/\b\w+\b/g) || []).length;
59+
+
60+
+ lines.textContent = totalLines.toString();
61+
+ words.textContent = totalWords.toString();
62+
+ cursor.textContent = `${line}:${column}`;
63+
+ }
64+
+
65+
+ textarea.addEventListener('input', updateStatus);
66+
+ textarea.addEventListener('click', updateStatus);
67+
+ textarea.addEventListener('keyup', updateStatus);
68+
+ updateStatus(); // Initial render
69+
+ })();
70+
+ </script>
71+
+
72+
</div>
73+
<div class="inline field">
74+
<div class="ui checkbox">
1175
diff --git a/web_src/js/components/PullRequestMergeForm.vue b/web_src/js/components/PullRequestMergeForm.vue
12-
index bafeec6c97..c409c12c6f 100644
76+
index bafeec6c97..6f8bcaa6cc 100644
1377
--- a/web_src/js/components/PullRequestMergeForm.vue
1478
+++ b/web_src/js/components/PullRequestMergeForm.vue
15-
@@ -26,6 +26,10 @@ const mergeStyleAllowedCount = ref(0);
79+
@@ -26,6 +26,12 @@ const mergeStyleAllowedCount = ref(0);
1680
const showMergeStyleMenu = ref(false);
1781
const showActionForm = ref(false);
1882

1983
+const mergeMessageTextarea = ref<HTMLTextAreaElement | null>(null);
2084
+const cursorLine = ref(1);
2185
+const cursorColumn = ref(1);
86+
+const wordCount = ref(1);
87+
+const lineCount = ref(1);
2288
+
2389
const mergeButtonStyleClass = computed(() => {
2490
if (mergeForm.value.allOverridableChecksOk) return 'primary';
2591
return autoMergeWhenSucceed.value ? 'primary' : 'red';
26-
@@ -76,6 +80,19 @@ function switchMergeStyle(name, autoMerge = false) {
92+
@@ -76,6 +82,23 @@ function switchMergeStyle(name, autoMerge = false) {
2793
function clearMergeMessage() {
2894
mergeMessageFieldValue.value = mergeForm.value.defaultMergeMessage;
2995
}
@@ -38,12 +104,16 @@ index bafeec6c97..c409c12c6f 100644
38104
+ const lines = value.substring(0, pos).split('\n');
39105
+ cursorLine.value = lines.length;
40106
+ cursorColumn.value = lines[lines.length - 1].length + 1;
107+
+
108+
+ // Full content stats
109+
+ lineCount.value = textarea.value.split('\n').length;
110+
+ wordCount.value = textarea.value.trim().split(/\s+/).filter(Boolean).length;
41111
+}
42112
+
43113
</script>
44114

45115
<template>
46-
@@ -105,7 +122,19 @@ function clearMergeMessage() {
116+
@@ -105,7 +128,22 @@ function clearMergeMessage() {
47117
<input type="text" name="merge_title_field" v-model="mergeTitleFieldValue">
48118
</div>
49119
<div class="field">
@@ -58,41 +128,99 @@ index bafeec6c97..c409c12c6f 100644
58128
+ @keyup="updateCursorPosition"
59129
+ @input="updateCursorPosition"
60130
+ />
61-
+ <div class="tw-mt-2 tw-text-sm tw-text-gray-500">
62-
+ Line: {{ cursorLine }}, Column: {{ cursorColumn }}
131+
+ <div class="editor-statusbar">
132+
+ <span class="autosave"></span>
133+
+ <span class="lines">{{ lineCount }}</span>
134+
+ <span class="words">{{ wordCount }}</span>
135+
+ <span class="cursor">{{ cursorLine }}:{{ cursorColumn }}</span>
63136
+ </div>
64137
<template v-if="mergeMessageFieldValue !== mergeForm.defaultMergeMessage">
65138
<button @click.prevent="clearMergeMessage" class="btn tw-mt-1 tw-p-1 interact-fg" :data-tooltip-content="mergeForm.textClearMergeMessageHint">
66139
{{ mergeForm.textClearMergeMessage }}
67140
diff --git a/web_src/js/features/comp/ComboMarkdownEditor.ts b/web_src/js/features/comp/ComboMarkdownEditor.ts
68-
index bba50a1296..0df15ca1b4 100644
141+
index bba50a1296..3252e68402 100644
69142
--- a/web_src/js/features/comp/ComboMarkdownEditor.ts
70143
+++ b/web_src/js/features/comp/ComboMarkdownEditor.ts
71-
@@ -161,6 +161,27 @@ export class ComboMarkdownEditor {
144+
@@ -69,6 +69,7 @@ export class ComboMarkdownEditor {
145+
easyMDE: any;
146+
easyMDEToolbarActions: any;
147+
easyMDEToolbarDefault: any;
148+
+ statusbarEl?: HTMLDivElement;
149+
150+
textarea: HTMLTextAreaElement & {_giteaComboMarkdownEditor: any};
151+
textareaMarkdownToolbar: HTMLElement;
152+
@@ -127,10 +128,10 @@ export class ComboMarkdownEditor {
153+
this.textareaMarkdownToolbar = this.container.querySelector('markdown-toolbar');
154+
this.textareaMarkdownToolbar.setAttribute('for', this.textarea.id);
155+
for (const el of this.textareaMarkdownToolbar.querySelectorAll('.markdown-toolbar-button')) {
156+
- // upstream bug: The role code is never executed in base MarkdownButtonElement https://github.com/github/markdown-toolbar-element/issues/70
157+
el.setAttribute('role', 'button');
158+
- // the editor usually is in a form, so the buttons should have "type=button", avoiding conflicting with the form's submit.
159+
- if (el.nodeName === 'BUTTON' && !el.getAttribute('type')) el.setAttribute('type', 'button');
160+
+ if (el.nodeName === 'BUTTON' && !el.getAttribute('type')) {
161+
+ el.setAttribute('type', 'button');
162+
+ }
163+
}
164+
165+
const monospaceButton = this.container.querySelector('.markdown-switch-monospace');
166+
@@ -153,6 +154,8 @@ export class ComboMarkdownEditor {
167+
easymdeButton.addEventListener('click', async (e) => {
168+
e.preventDefault();
169+
this.userPreferredEditor = 'easymde';
170+
+ // Clear statusbar if switching to EasyMDE
171+
+ if (this.statusbarEl) this.statusbarEl.remove();
172+
await this.switchToEasyMDE();
173+
});
174+
}
175+
@@ -161,6 +164,51 @@ export class ComboMarkdownEditor {
72176

73177
initTextareaMarkdown(this.textarea);
74178
initTextareaEvents(this.textarea, this.dropzone);
75179
+
76-
+ // Cursor Position Tracker
77-
+ const positionDisplay = document.createElement('div');
78-
+ positionDisplay.className = 'tw-mt-2 tw-text-sm tw-text-gray-500';
79-
+ this.container.appendChild(positionDisplay);
180+
+ // === Status bar setup ===
181+
+ const statusbar = document.createElement('div');
182+
+ statusbar.className = 'editor-statusbar';
183+
+
184+
+ const autosave = document.createElement('span');
185+
+ autosave.className = 'autosave';
186+
+
187+
+ const linesEl = document.createElement('span');
188+
+ linesEl.className = 'lines';
80189
+
81-
+ const updateCursorPosition = () => {
190+
+ const wordsEl = document.createElement('span');
191+
+ wordsEl.className = 'words';
192+
+
193+
+ const cursorEl = document.createElement('span');
194+
+ cursorEl.className = 'cursor';
195+
+
196+
+ statusbar.appendChild(autosave);
197+
+ statusbar.appendChild(linesEl);
198+
+ statusbar.appendChild(wordsEl);
199+
+ statusbar.appendChild(cursorEl);
200+
+ this.container.appendChild(statusbar);
201+
+ this.statusbarEl = statusbar; // So we can remove it when switching to EasyMDE
202+
+
203+
+ const updateStatus = () => {
82204
+ const value = this.textarea.value;
83205
+ const pos = this.textarea.selectionStart;
84206
+
85207
+ const lines = value.substr(0, pos).split('\n');
86208
+ const line = lines.length;
87209
+ const column = lines[lines.length - 1].length + 1;
88210
+
89-
+ positionDisplay.textContent = `Line: ${line}, Column: ${column}`;
211+
+ const totalLines = value.split('\n').length;
212+
+ const totalWords = (value.match(/\b\w+\b/g) || []).length;
213+
+
214+
+ linesEl.textContent = totalLines.toString();
215+
+ wordsEl.textContent = totalWords.toString();
216+
+ cursorEl.textContent = `${line}:${column}`;
90217
+ };
91218
+
92-
+ this.textarea.addEventListener('input', updateCursorPosition);
93-
+ this.textarea.addEventListener('click', updateCursorPosition);
94-
+ this.textarea.addEventListener('keyup', updateCursorPosition);
95-
+ updateCursorPosition();
219+
+ this.textarea.addEventListener('input', updateStatus);
220+
+ this.textarea.addEventListener('click', updateStatus);
221+
+ this.textarea.addEventListener('keyup', updateStatus);
222+
+ updateStatus();
223+
+
96224
}
97225

98226
async setupDropzone() {

0 commit comments

Comments
 (0)