Skip to content
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

web/app: folding support #84

Merged
merged 14 commits into from
Nov 28, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
37 changes: 37 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,40 @@
## 0.6.2

Notesium now supports **section folding** in the web/app editor, making
it easier to view and edit your notes, especially longer ones. Folds can
be toggled via the Fold gutter or keybindings, which work whether the
cursor is on the section heading or anywhere within the section.

Folded sections are visually distinct, featuring a subtle full-width
background, displaying the line count, and unfolding when clicked.

Fixed:

- Web/App: Sidepanel - support capitalized labels in labelQuery filter.
- Web/App: Sidepanel - deduplicate labels for detailed view and searchStr.
- Web/App: Sidepanel - use deduplicated linked notes over note links.

Added:

- Web/App: Fold - section folding support in Editor.
- Web/App: Fold - fold-marker with header text and line count.
- Web/App: Fold - fold-marker with full-width subtle background.
- Web/App: Fold - fold-marker readonly when folded, click to unfold.
- Web/App: Fold - toggle keybinding for section folds (`C-Enter`).
- Web/App: Fold - vimmode keybindings (`za zo zc zR zM`).
- Web/App: Fold - scanUp on folding (cursor on header or in section).
- Web/App: FoldGutter - displays collapsible sections, click to toggle.
- Web/App: FoldGutter - vimMode command to set `[no]fold`.
- Web/App: FoldGutter - state setting in **Settings:Editor**.
- Web/App: FoldGutter - state toggle in **StatusBar**.

- Web/App: Sidepanel - include finder list-links icon in labelTree labels.

Changed:

- Web/App: Note sidebar - removed editor options included in Statusbar.
- Web/App: Vendor - upgraded to `alonswartz/notesium-cm5` v5.65.18-2.

## 0.6.1

This release focuses on enhancements to the web/app editor,
Expand Down
30 changes: 30 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@ It aspires and is designed to:
- [Finder](#finder)
- [Editor modes](#editor-modes)
- [Table formatting and navigation](#table-formatting-and-navigation)
- [Section folding](#section-folding)
- [Syntax highlighting and concealment](#syntax-highlighting-and-concealment)
- [Vim](#vim)
- [Example integration](#example-integration)
Expand Down Expand Up @@ -108,6 +109,7 @@ It aspires and is designed to:
- Create and edit notes with web based editor (optional vim-mode).
- Markdown syntax highlighting, special char and links concealment.
- Markdown table formatting and navigation.
- Markdown section folding with optional fold gutter.
- Open multiple notes in tabs, drag to re-order, keybindings to switch.
- Finder integration for List, Links and Lines with preview.
- Note deletion with incoming-links verification and confirmation.
Expand Down Expand Up @@ -378,6 +380,7 @@ ribbon, but is also seamlessly integrated throughout the web interface.
| edit | `Shift-Tab` | Auto-indent current line or selection
| edit | `C-]` | Indent current line or selection
| edit | `C-[` | Dedent current line or selection
| edit | `C-Enter` | Toggle section fold
| edit | `Esc` | Exit editing mode (unfocus)

**Vim mode**
Expand All @@ -391,6 +394,7 @@ implementation. It does however feature the following:
- Commands for write and quit (:w :wq :q :q!)
- Visual mode - characterwise, linewise, blockwise
- Full macro support (q @)
- Folding support (za zo zc zR zM)
- Incremental highlighted search (/ ? # * g# g*)
- Search/replace with confirm (:substitute :%s)
- Search history
Expand All @@ -406,10 +410,12 @@ implementation. It does however feature the following:
| all | `C-l` `C-h` `C-6` | Note tab keybinds passthrough
| normal | `space n <char>` | Global keybinds passthrough
| normal | `ge` `gx` | Open link under cursor
| normal | `z<char>` | Fold, unfold, toggle sections
| insert | `[[` | Insert selected note link via Finder (mtime sorted)
| insert | `Alt-k` | Insert selected note link via Finder (mtime sorted)
| command | `:set [no]wrap` | Set line wrapping
| command | `:set [no]conceal` | Set conceal formatting
| command | `:set [no]fold` | Set fold gutter

Prefer the *real thing*? Notesium supports [Vim integration](#vim).

Expand Down Expand Up @@ -444,6 +450,30 @@ provide formatting and navigation.
| table | `Shift-Tab` | Navigate to previous column (left)
| table | `Alt-Arrow` | Navigate rows and columns

### Section folding

The editor supports section folding, making it easier to view and edit
notes, especially longer ones. Folds can be toggled via the Fold
gutter or keybindings, which work whether the cursor is on the section
heading or anywhere within the section.

The Fold gutter displays chevrons for collapsible sections. Clicking a
chevron toggles folding for that section. The Fold gutter can be enabled
in **Settings:Editor**, the Editor **Statusbar** or the Vim mode command
`:set [no]fold`.

Folded sections are visually distinct, featuring a subtle full-width
background, displaying the line count, and unfolding when clicked.

| Mode | Binding | Comment
| ---- | -------- | -------
| default | `C-Enter` | Toggle section fold
| vim-normal | `za` | Toggle section fold
| vim-normal | `zc` | Close section fold
| vim-normal | `zo` | Open section fold
| vim-normal | `zM` | Close all section folds
| vim-normal | `zR` | Open all section folds

### Syntax highlighting and concealment

The editor is configured to syntax highlight based on Markdown
Expand Down
16 changes: 16 additions & 0 deletions web/app/cm-vim.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,15 @@ export function initCodeMirrorVimEx(notesiumState) {
if (cm.writequit) cm.writequit();
});

CodeMirror.Vim.defineEx('cmExecCommand', '', (cm, cmd) => {
cm.execCommand(cmd.args[0]);
});
CodeMirror.Vim.map('zo', ':cmExecCommand unfold', 'normal');
CodeMirror.Vim.map('zc', ':cmExecCommand fold', 'normal');
CodeMirror.Vim.map('zR', ':cmExecCommand unfoldAll', 'normal');
CodeMirror.Vim.map('zM', ':cmExecCommand foldAll', 'normal');
CodeMirror.Vim.map('za', ':cmExecCommand toggleFold', 'normal');

CodeMirror.Vim.defineEx('OpenLinkUnderCursor', '', (cm) => {
if (!cm.openlink) return;
const cursor = cm.getCursor();
Expand Down Expand Up @@ -62,4 +71,11 @@ export function initCodeMirrorVimEx(notesiumState) {
notesiumState.editorConcealFormatting = value;
return value;
});

CodeMirror.Vim.defineOption('fold', notesiumState.editorFoldGutter, 'boolean', [], (value, cm) => {
if (cm) return; // option is global, do nothing for local
if (value === undefined) return notesiumState.editorFoldGutter;
notesiumState.editorFoldGutter = value;
return value;
});
}
36 changes: 35 additions & 1 deletion web/app/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@

.cm-links-hover span.cm-url:hover,
.cm-links-hover span.cm-link:hover { cursor: pointer; text-decoration: underline; }
.cm-fat-cursor .CodeMirror-cursor { background: #cbd5e1; }
.cm-fat-cursor .CodeMirror-cursor { background: #cbd5e1; max-width: 8px; }

.cm-conceal .CodeMirror span.cm-url,
.cm-conceal .CodeMirror span.cm-formatting-em,
Expand Down Expand Up @@ -74,6 +74,40 @@
font-family: monospace;
caret-color: black;
}

.cm-s-notesium-light .CodeMirror-gutters { background-color: transparent; border-right: 0px; }
.cm-s-notesium-light .CodeMirror-guttermarker-subtle { color: #d1d5db; cursor: pointer; }
.cm-s-notesium-light .CodeMirror-guttermarker-subtle:hover { color: black; }
.CodeMirror-foldgutter { width: 1.5em; }
.CodeMirror-foldgutter-open:after,
.CodeMirror-foldgutter-folded:after {
content: "\203A";
display: inline-block;
font-size: 24px;
line-height: 1;
margin-top: -3px;
}
.CodeMirror-foldgutter-open:after {
margin-left: 1px;
transform: rotate(90deg);
}
.cm-foldmarker {
cursor: pointer;
display: inline-block;
width: 98%;
background-color: #e4e4e790;
margin-bottom: 1px;
}
.cm-foldmarker:hover {
background-color: #e4e4e7;
}
.cm-foldmarker-header {
font-weight: bold;
}
.cm-foldmarker-lines {
padding-left: 10px;
opacity: 50%;
}
</style>
</head>
<body tabindex="-1">
Expand Down
4 changes: 2 additions & 2 deletions web/app/make.sh
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,8 @@ CM="https://github.com/alonswartz/notesium-cm5/releases/download"
D3="https://cdnjs.cloudflare.com/ajax/libs/d3"
cat<<EOF
628497cb69df7b1d31236479cad68c9bb3f265060afd5506a0c004b394dfa47e https://unpkg.com/vue@3.3.4/dist/vue.global.prod.js
70cc19b59cc89262bb286de075ed517a634768cb77386c5ab1b950cd63882dd2 $CM/v5.65.18-1/notesium-cm5.min.js
4d507d755e1d3188bd1e95d67b8bc9efd0094576135006fce68c5e9d44303061 $CM/v5.65.18-1/notesium-cm5.min.css
9571811ec12dbfe62834171349cf64bfa206ebd3d2519c16d2b3be4b5862b966 $CM/v5.65.18-2/notesium-cm5.min.js
4d507d755e1d3188bd1e95d67b8bc9efd0094576135006fce68c5e9d44303061 $CM/v5.65.18-2/notesium-cm5.min.css
d6b03aefc9f6c44c7bc78713679c78c295028fa914319119e5cc4b4954855b1c $D3/7.8.5/d3.min.js
EOF
}
Expand Down
18 changes: 5 additions & 13 deletions web/app/note-sidebar.js
Original file line number Diff line number Diff line change
@@ -1,20 +1,12 @@
var t = `
<Pane name="noteSidebar" :defaultWidth="384" :minWidth="200" direction="left">
<aside class="h-full overflow-y-auto my-2 mr-2 rounded-lg border border-gray-200 bg-white">
<Pane name="noteSidebar" :defaultWidth="384" :minWidth="245" direction="left">
<aside class="h-full overflow-y-auto mt-2 mr-2 rounded-t-lg border border-gray-200 bg-white">

<div class="flex flex-wrap gap-x-5 gap-y-2 p-2 border-b sticky top-0 z-10 bg-white">
<div class="flex gap-x-5 gap-y-2 p-2 border-b sticky top-0 z-10 bg-white">
<button type="button" :disabled="!note.isModified" @click="$emit('note-save')"
:class="note.isModified ? 'bg-blue-600 hover:bg-blue-500 text-white' : 'bg-gray-300 text-gray-400'"
class="flex-grow max-w-xs rounded px-2 pt-2 pb-1 text-xs shadow-sm">Save</button>
<div class="flex flex-wrap w-auto gap-x-5 gap-y-2 mt-0 ml-auto items-center justify-center">
<span title="conceal formatting" @click="$notesiumState.editorConcealFormatting = !$notesiumState.editorConcealFormatting"
class="cursor-pointer text-gray-400 hover:text-gray-700">
<Icon name="outline-code" size="h-4 w-4" />
</span>
<span title="line wrapping" @click="$notesiumState.editorLineWrapping = !$notesiumState.editorLineWrapping"
class="cursor-pointer text-gray-400 hover:text-gray-700 rotate-180">
<Icon name="micro-arrow-uturn-right" size="h-3 w-3" />
</span>
class="w-28 rounded px-2 pt-2 pb-1 text-xs shadow-sm">Save</button>
<div class="flex gap-x-5 gap-y-2 mt-0 ml-auto items-center justify-center">
<span title="links" @click="$emit('finder-open', '/api/raw/links?color=true&filename=' + note.Filename)"
class="cursor-pointer text-gray-400 hover:text-gray-700">
<Icon name="mini-arrows-right-left" size="h-3 w-3" />
Expand Down
4 changes: 3 additions & 1 deletion web/app/note-statusbar.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,13 +15,15 @@ var t = `
class="cursor-pointer hover:text-gray-700" v-text="$notesiumState.editorLineWrapping ? 'wrap' : 'nowrap'" />
<span title="conceal formatting" @click="$notesiumState.editorConcealFormatting = !$notesiumState.editorConcealFormatting"
class="cursor-pointer hover:text-gray-700" v-text="$notesiumState.editorConcealFormatting ? 'conceal' : 'noconceal'" />
<span title="fold gutter" @click="$notesiumState.editorFoldGutter = !$notesiumState.editorFoldGutter"
class="cursor-pointer hover:text-gray-700" v-text="$notesiumState.editorFoldGutter ? 'fold' : 'nofold'" />
<template v-if="!note.ghost && !$notesiumState.showNoteSidebar">
<span title="incoming links" class="cursor-pointer hover:text-gray-700 -mb-px"
@click="$emit('finder-open', '/api/raw/links?color=true&incoming=true&filename=' + note.Filename)">
{{note.IncomingLinks?.length || 0}}&swarr;
</span>
<span title="outgoing links" class="cursor-pointer hover:text-gray-700 -mb-px"
@click="$emit('finder-open', '/api/raw/links?color=true&&outgoing=true&filename=' + note.Filename)">
@click="$emit('finder-open', '/api/raw/links?color=true&outgoing=true&filename=' + note.Filename)">
{{note.OutgoingLinks?.length || 0}}&nearr;
</span>
<span title="links" @click="$emit('finder-open', '/api/raw/links?color=true&filename=' + note.Filename)"
Expand Down
37 changes: 36 additions & 1 deletion web/app/note.js
Original file line number Diff line number Diff line change
Expand Up @@ -147,6 +147,30 @@ export default {
this.vimMode = null;
}
},
handleEditorFoldGutter() {
if (this.$notesiumState.editorFoldGutter) {
this.cm.setOption("gutters", ["CodeMirror-foldgutter"]);
this.cm.setOption("foldGutter", true);
} else {
this.cm.setOption("gutters", []);
this.cm.setOption("foldGutter", false);
}
},
foldWidget(from, to) {
var header = document.createElement("span");
header.appendChild(document.createTextNode(this.cm.getLine(from.line).trim()));
header.className = "cm-foldmarker-header";

var lines = document.createElement("span");
lines.appendChild(document.createTextNode(`[${to.line - from.line} lines]`));
lines.className = "cm-foldmarker-lines";

var widget = document.createElement("span");
widget.appendChild(header);
widget.appendChild(lines);
widget.className = "cm-foldmarker";
return widget;
},
lineNumberHL(linenum) {
if (!Number.isInteger(linenum) || linenum === undefined) return;
this.$nextTick(() => {
Expand Down Expand Up @@ -174,6 +198,14 @@ export default {
lineNumbers: false,
lineWrapping: this.$notesiumState.editorLineWrapping,
styleActiveLine: false,
foldOptions: {
rangeFinder: CodeMirror.fold.markdown,
markdownIncludeHeader: true,
widget: this.foldWidget,
inclusiveRight: true,
clearOnEnter: false,
scanUp: true,
},
tabSize: 4,
indentUnit: 4,
theme: 'notesium-light',
Expand All @@ -186,6 +218,7 @@ export default {
"Ctrl-S": this.handleSave,
"Tab": this.handleTab,
"Backspace": this.handleBackspace,
"Ctrl-Enter": function(cm) { return cm.execCommand('toggleFold'); },
"Shift-Tab": function(cm) { return Table.navigateTable(cm, 'left'); },
"Alt-Up": function(cm) { return Table.navigateTable(cm, 'up'); },
"Alt-Down": function(cm) { return Table.navigateTable(cm, 'down'); },
Expand Down Expand Up @@ -282,6 +315,7 @@ export default {
});

this.handleEditorVimMode();
this.handleEditorFoldGutter();
document.addEventListener('keydown', this.handleKeyPress);
},
beforeDestroy() {
Expand All @@ -292,7 +326,8 @@ export default {
'note.Linenum': function(newVal) { this.lineNumberHL(newVal); if (this.$notesiumState.editorVimMode) this.$nextTick(() => { this.cm.focus(); }); },
'note.Mtime': function() { this.cm.doc.markClean(); },
'$notesiumState.editorLineWrapping': function(newVal) { this.cm.setOption("lineWrapping", newVal); },
'$notesiumState.editorVimMode': function() { this.handleEditorVimMode(); }
'$notesiumState.editorVimMode': function() { this.handleEditorVimMode(); },
'$notesiumState.editorFoldGutter': function() { this.handleEditorFoldGutter(); },
},
template: t
}
5 changes: 5 additions & 0 deletions web/app/settings-editor.js
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ var t = `
<li>Commands for write and quit (:w :wq :q :q!)</li>
<li>Visual mode - characterwise, linewise, blockwise</li>
<li>Full macro support (q @)</li>
<li>Folding support (za zo zc zR zM)</li>
<li>Incremental highlighted search (/ ? # * g# g*)</li>
<li>Search/replace with confirm (:substitute :%s)</li>
<li>Search history</li>
Expand Down Expand Up @@ -105,6 +106,7 @@ export default {
{name: 'editorVimMode', title: 'Vim mode'},
{name: 'editorLineWrapping', title: 'Line wrapping'},
{name: 'editorConcealFormatting', title: 'Conceal formatting'},
{name: 'editorFoldGutter', title: 'Fold gutter'},
]
},
keymaps: [
Expand All @@ -119,6 +121,7 @@ export default {
['Shift-Tab', 'Auto-indent current line or selection', 'edit'],
['C-]', 'Indent current line or selection', 'edit'],
['C-[', 'Dedent current line or selection', 'edit'],
['C-Enter', 'Toggle section fold', 'edit'],
['Esc', 'Exit editing mode (unfocus)', 'edit'],
]
},
Expand All @@ -132,10 +135,12 @@ export default {
['C-h C-l C-6', 'Note tab keybinds passthrough', 'all'],
['space n <char>', 'Global keybinds passthrough', 'normal'],
['ge | gx', 'Open link under cursor', 'normal'],
['z<char> | C-Enter', 'Fold, unfold, toggle sections', 'normal'],
['[[', 'Insert selected note link via Finder (mtime sorted)', 'insert'],
['Alt-k', 'Insert selected note link via Finder (mtime sorted)', 'insert'],
[':set [no]wrap', 'Set line wrapping', 'command'],
[':set [no]conceal', 'Set conceal formatting', 'command'],
[':set [no]fold', 'Set fold gutter', 'command'],
]
},
{
Expand Down
1 change: 1 addition & 0 deletions web/app/state.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ const defaultState = {
notesPanelCompactLabels: true,
sidePanelSortNotes: 'title', // title, links, mtime, ctime
sidePanelSortLabels: 'title', // title, links
editorFoldGutter: false,
editorLineWrapping: false,
editorConcealFormatting: true,
editorVimMode: false,
Expand Down
Loading