Merge changes Ia6823f9d,I549e570f,Ibcac9d5e,I75c48a1c into stable-3.12
* changes:
Resize CodeMirror dynamically
Remove outline on textbox
Display cursor position in the bottom
Fix going to line
diff --git a/web/element/codemirror-element.ts b/web/element/codemirror-element.ts
index d608598..27c6ef2 100644
--- a/web/element/codemirror-element.ts
+++ b/web/element/codemirror-element.ts
@@ -57,8 +57,13 @@
@query('#wrapper')
wrapper!: HTMLElement;
+ @query('#result')
+ result!: HTMLElement;
+
private initialized = false;
+ private onResize: (() => void) | null = null;
+
static override get styles() {
return [
css`
@@ -75,12 +80,36 @@
font-family: 'Roboto Mono', 'SF Mono', 'Lucida Console', Monaco,
monospace;
}
+ #statusLine {
+ position: absolute;
+ bottom: 0;
+ left: 0;
+ width: 100%;
+ background-color: #f7f7f7;
+ border-top: 1px solid #ddd;
+ border-right: 1px solid #ddd;
+ }
+ #statusLine div {
+ height: inherit;
+ }
+ .cursorPosition {
+ display: inline-block;
+ margin: 0 5px 0 35px;
+ white-space: nowrap;
+ }
`,
];
}
override render() {
- return html`<div id="wrapper"></div>`;
+ return html`
+ <div id="wrapper"></div>
+ <div class="statusLine">
+ <div class="cursorPosition">
+ <span id="result"></span>
+ </div>
+ </div>
+ `;
}
override updated() {
@@ -93,20 +122,12 @@
if (this.initialized) return;
this.initialized = true;
- const offsetTop = this.getBoundingClientRect().top;
- const clientHeight = window.innerHeight ?? document.body.clientHeight;
- // We are setting a fixed height, because for large files we want to
- // benefit from CodeMirror's virtual scrolling.
- // 80px is roughly the size of the bottom margins plus the footer height.
- // This ensures the height of the textarea doesn't push out of screen.
- const height = clientHeight - offsetTop - 80;
-
const editor = new EditorView({
state: EditorState.create({
doc: this.fileContent ?? '',
extensions: [
...extensions(
- height,
+ this.calculateHeight(),
this.prefs,
this.fileType,
this.fileContent ?? '',
@@ -154,6 +175,11 @@
}
},
}),
+ EditorView.updateListener.of(update => {
+ if (update.selectionSet) {
+ this.updateCursorPosition(update.view);
+ }
+ }),
],
}),
parent: this.wrapper as Element,
@@ -162,9 +188,65 @@
editor.focus();
if (this.lineNum) {
- // We have to take away one from the line number,
- // ... because CodeMirror's line count is zero-based.
- editor.dispatch({selection: {anchor: this.lineNum - 1}});
+ this.setCursorToLine(editor, this.lineNum);
+ }
+
+ // Makes sure to show line number and column number on initial
+ // load.
+ this.updateCursorPosition(editor);
+
+ this.onResize = () => this.updateEditorHeight(editor);
+ window.addEventListener('resize', this.onResize);
+ }
+
+ override disconnectedCallback() {
+ super.disconnectedCallback();
+ if (this.onResize) {
+ window.removeEventListener('resize', this.onResize);
+ this.onResize = null;
+ }
+ }
+
+ setCursorToLine(view: EditorView, lineNum: number) {
+ const totalLines = view.state.doc.lines;
+ // If you try going to a line that does not exist
+ // codemirror will error out. Instead lets just log.
+ // Line 1 will be selected automatically.
+ if (lineNum < 1 || lineNum > totalLines) {
+ console.warn(`Line number ${lineNum} is out of bounds (valid range: 1 - ${totalLines}).`);
+ return;
+ }
+
+ const line = view.state.doc.line(lineNum);
+ view.dispatch({
+ selection: { anchor: line.from },
+ scrollIntoView: true
+ });
+ view.focus();
+ }
+
+ private updateCursorPosition(view: EditorView) {
+ const cursor = view.state.selection.main.head;
+ const line = view.state.doc.lineAt(cursor);
+ if (this.result) {
+ this.result.textContent = `Line: ${line.number}, Column: ${cursor - line.from + 1}`;
+ }
+ }
+
+ private calculateHeight() {
+ const offsetTop = this.getBoundingClientRect().top;
+ const clientHeight = window.innerHeight ?? document.body.clientHeight;
+ // We take offsetTop twice to ensure the height of the texarea doesn't push
+ // out of screen. We no longer do a hardcore value which was 80 before.
+ // offsetTop seems to be what we've been looking for to do it dynamically.
+ return Math.max(0, clientHeight - offsetTop - offsetTop);
+ }
+
+ private updateEditorHeight(editor: EditorView) {
+ const height = this.calculateHeight();
+ const editorElement = editor.dom;
+ if (editorElement) {
+ editorElement.style.height = `${height}px`;
}
}
}
diff --git a/web/element/extensions.ts b/web/element/extensions.ts
index 64b998c..6c2be75 100644
--- a/web/element/extensions.ts
+++ b/web/element/extensions.ts
@@ -47,6 +47,9 @@
color: 'var(--deemphasized-text-color)',
'background-color': 'var(--background-color-secondary)',
},
+ '&.cm-editor.cm-focused': {
+ outline: 'none'
+ },
},
{dark}
);