Skip to content

Commit

Permalink
feat: generate note regex, docs
Browse files Browse the repository at this point in the history
  • Loading branch information
prmichaelsen committed Sep 4, 2023
1 parent f91fc9c commit 7b24220
Show file tree
Hide file tree
Showing 14 changed files with 229 additions and 77 deletions.
8 changes: 8 additions & 0 deletions .vscode/.linenoteplus/getNotePrefixNote.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
Note: It may not actually be a good idea
to make this setting configurable.

This could cause issues in shared repositories
where one user has customized their note prefix
and others have not. In order to ameliorate this
issue, workspace settings would have to be committed
which does not feel ideal for such a simple plugin.
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -34,3 +34,7 @@
- Fixed a bug that range of hyperlink in the note is wrong
- Fixed a bug that was incorrectly parsed when using # in markdown links
- Fixed a bug that can not open hyperlink to another file in the note

## [2.0.0]

Breaks backwards compatability. Feature overhaul into "Line Note Plus"
69 changes: 64 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
# Line Note Plus

Line Note Plus is a VSCode extension to add Markdown notes to your code
that are visible when hovering over the noted line.
that are visible when hovering over the noted line. Based on [Line Note](https://github.com/tkrkt/linenote).

<img width="1090" alt="basic-demo" src="https://github.com/prmichaelsen/linenoteplus/assets/8428140/0ecb3057-2334-4413-b0aa-71889ae14a6b">

[VSCode Marketplace](https://marketplace.visualstudio.com/items?itemName=prmichaelsen.linenoteplus)

Expand All @@ -10,8 +12,65 @@ that are visible when hovering over the noted line.
Invoke `Add note at current position` from the command palette or context menu.
You can see the note you wrote as hover text.

Notes are saved in `$PROJECT_ROOT/.vscode/linenoteplus` like `.vscode/linenoteplus/<short-uid>.md`.
Notes are saved in `$PROJECT_ROOT/.vscode/.linenoteplus` like `.vscode/.linenoteplus/<short-uid>.md`.

### Overview
* Edit/open or remove note via Cmd + Click
* Markdown note previews on hover
* Right-click to add note to line
* Right-click to reveal notated line
* Custom note names
* Command to add note
* Command to edit/open note
* Command to remove note
* Command to reveal notated line
* Notes move with code changes
* Notes can be moved between files
* Notes are not affected by refactors

### API
#### Commands
* `linenouteplus.addNote`: Add note at current position (Annotate Line)
* `linenouteplus.openNote`: Edit note at current position (Open Note)
* `linenouteplus.revealLine`: Reveal line in notated file (Show Note Marker)
* `linenouteplus.removeNote`: Remove note at current position (Delete Note)

#### Configuration
- `linenoteplus.cleanUpOrphanedNotesInterval`: Interval at which to clean up unused notes in the background in ms. Only applies if `cleanUpOrphanedNotes` is set to `on-interval` or `on-save-and-on-interval`. Default: `60000` (60s). For performance, a larger value is recommended.
- `linenoteplus.cleanUpOrphanedNotes`: Defines the cleanup behavior for orphaned notes. It can be set to `on-save`, `on-interval`, `on-save-and-on-interval`, or `never`. Default: `on-save-and-on-internal`. Note that when using `on-save` or `on-save-and-on-interval`, if you delete a note marker and save the file then your note file will also be deleted.
- `linenoteplus.includePaths`: Specifies file pattern globs to scan for note markers. Directories that don't match these patterns will be ignored.
- `linenoteplus.gutterIconPath`: File path of the icon to be displayed in gutter.
- `linenoteplus.lineColor`: Sets the background color for inline note markers (Name, HEX, or RGB).
- `linenoteplus.rulerColor`: Sets the ruler color for notated lines (Name, HEX, or RGB).
- `linenoteplus.showGutterIcon`: Whether to display the gutter icon in the gutter for a noted line. Default: `true`.

### Demos
#### Adding a note
![add-note](https://github.com/prmichaelsen/linenoteplus/assets/8428140/85a41396-6ea5-4621-9621-ac77972448b1)

#### Custom note title
![custom-name](https://github.com/prmichaelsen/linenoteplus/assets/8428140/558907e7-538a-49c3-9099-45daed825b37)

#### Notes move with code changes
![moves-with-code](https://github.com/prmichaelsen/linenoteplus/assets/8428140/569280b2-3b65-4872-8a8a-85d5011c8f8c)

#### Notes can be moved across files
![move-notes-across-files](https://github.com/prmichaelsen/linenoteplus/assets/8428140/cdb578c8-7a0f-4894-ad4c-dba5f71f2d00)


#### Reveal notated line command
![reveal-notated-file](https://github.com/prmichaelsen/linenoteplus/assets/8428140/e3d4f76a-67e1-4603-abd4-8a3dcedec15a)

#### Refactor does not affect notes
![refactor-does-not-affect-notes](https://github.com/prmichaelsen/linenoteplus/assets/8428140/d034f397-ebd7-4fa6-9843-4cb3f2c26c9e)


### Acknowledgements
Line Note Plus is a fork of Line Note by tkrkt. This library's design
was also informed by Marginalia by indiejames.
* https://github.com/tkrkt/linenote
* https://github.com/indiejames/marginalia


### Demo
* Adding and removeing notes: https://storage.googleapis.com/com-f5-parm.appspot.com/parm/images/XK7AHFrBrfD7LpliwDX5.quicktime
* Notes move with code: https://storage.googleapis.com/com-f5-parm.appspot.com/parm/images/KbetjziHdRWmfHpJu5FN.quicktime
### Known Bugs
* Gutter icon does not display.
35 changes: 27 additions & 8 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,9 +1,26 @@
{
"name": "linenoteplus",
"displayName": "Line Note Plus",
"description": "Add notes to the line of source code",
"version": "1.2.2",
"description": "Annotate lines of code with Markdown notes visible on hover.",
"version": "2.1.0",
"publisher": "prmichaelsen",
"author": {
"name": "Patrick Michaelsen",
"email": "[email protected]",
"url": "https://github.com/prmichaelsen"
},
"contributors": [
{
"name": "James Norton",
"email": "[email protected]",
"url": "https://github.com/indiejames"
},
{
"name": "tkrkt",
"url": "https://github.com/tkrkt"
}
],
"readme": "./README.md",
"engines": {
"vscode": "^1.30.0"
},
Expand All @@ -13,20 +30,22 @@
"license": "MIT",
"icon": "images/icon.png",
"activationEvents": [
"*"
"onStartupFinished"
],
"repository": {
"type": "git",
"url": "https://github.com/prmichaelsen/linenoteplus.git"
},
"bugs": {
"url": "https://github.com/prmichaelsen/linenoteplus/issues",
"email": "[email protected]"
},
"keywords": [
"vscode",
"note",
"comment",
"notataion",
"annotation",
"line",
"tooltip"
"sidenotes",
"marginalia"
],
"main": "./out/extension.js",
"contributes": {
Expand Down Expand Up @@ -105,7 +124,7 @@
"type": "array",
"default": [
"**/src/**/*",
"**/.vscode/linenoteplus/**/*"
"**/.vscode/.linenoteplus/**/*"
],
"description": "%configuration.includePaths.description%"
}
Expand Down
22 changes: 11 additions & 11 deletions package.nls.json
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
{
"command.addNote.title": "Line Note Plus: Add note at current position",
"command.openNote.title": "Line Note: Edit note at current position",
"command.revealLine.title": "Line Note Plus: Reveal line in notated file",
"command.removeNote.title": "Line Note Plus: Remove note at current position",
"configuration.cleanUpOrphanedNotesInterval.description": "Interval at which to clean up unused notes in the background in ms. Only applies if cleanupOprhanedNotes is set to 'on-interval' or 'on-save-and-on-interval'. Default: 60000 (60s). For performance, a large value is recommended. In order to determine if a note has a corresponding marker, the entire project directory must be scanned.",
"configuration.cleanUpOrphanedNotes.description": "Whether to cleanup orphaned notes on save file, on change file, on an interval, or never. Default: 'on-save'. Warning: On change file will provide more realtime updates but may affect performance and will delete note files instantly if not found in the changed file. Requires reload.",
"configuration.includePaths.description": "File pattern globs to scan for note markers. Unmatched directories will be ignored.",
"configuration.gutterIconPath.description": "File path of the icon to be displayed",
"configuration.lineColor.description": "Background color of line with notes (name, HEX, or RGB)",
"configuration.rulerColor.description": "Color of the ruler with notes (name, HEX, or RGB)",
"configuration.showGutterIcon.description": "If it set to true, displays the icon on the line where the note exists. Default true."
"command.addNote.title": "Line Note Plus: Add note at current position (Annotate Line)",
"command.openNote.title": "Line Note Plus: Edit note at current position (Open Note)",
"command.revealLine.title": "Line Note Plus: Reveal line in notated file (Show Note Marker)",
"command.removeNote.title": "Line Note Plus: Remove note at current position (Delete Note)",
"configuration.cleanUpOrphanedNotesInterval.description": "Interval at which to clean up unused notes in the background in ms. Only applies if `cleanUpOrphanedNotes` is set to `on-interval` or `on-save-and-on-interval`. Default: `60000` (60s). For performance, a larger value is recommended.",
"configuration.cleanUpOrphanedNotes.description": "Defines the cleanup behavior for orphaned notes. It can be set to `on-save`, `on-interval`, `on-save-and-on-interval`, or `never`. Default: `on-save-and-on-internal`. Note that when using `on-save` or `on-save-and-on-interval`, if you delete a note marker and save the file then your note file will also be deleted.",
"configuration.includePaths.description": "Specifies file pattern globs to scan for note markers. Directories that don't match these patterns will be ignored.",
"configuration.gutterIconPath.description": "File path of the icon to be displayed in gutter.",
"configuration.lineColor.description": "Sets the background color for inline note markers (Name, HEX, or RGB).",
"configuration.rulerColor.description": "Sets the ruler color for notated lines (Name, HEX, or RGB).",
"configuration.showGutterIcon.description": "Whether to display the gutter icon in the gutter for a noted line. Default: `true`."
}
2 changes: 1 addition & 1 deletion src/DocumentLinkProvider.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { DocumentLink, DocumentLinkProvider, Position, ProviderResult, Range, TextDocument, Uri } from "vscode";
import { Note } from "./note";
import { getNotePrefix } from "./util";
import { getNotePrefix } from "./noteUtil";

export const editText = '[Edit]';
export const removeText = '[Remove]';
Expand Down
3 changes: 2 additions & 1 deletion src/decorator.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import * as vscode from "vscode";
import { filterResolved, getNotesDir, splitArr } from "./util";
import { filterResolved, splitArr } from "./util";
import { Note } from "./note";
import { getNotesDir } from "./noteUtil";

export class Decorator {
context: vscode.ExtensionContext;
Expand Down
3 changes: 1 addition & 2 deletions src/editorUtil.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,7 @@
import * as vscode from 'vscode';
import { Note } from './note';
import { getOrphanedUuidsForCurDoc, isNotePath } from './noteUtil';
import { getNotesDir, getOrphanedUuidsForCurDoc, isNotePath } from './noteUtil';
import { globalActiveNoteMarkers } from './extension';
import { getNotesDir } from './util';


export const getEditor = () => {
Expand Down
10 changes: 6 additions & 4 deletions src/extension.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,11 +10,13 @@ import { CleanUpOrphanedNodesConf, getEditor, onDidSaveTextDocument, updateIsAct
import { Note } from "./note";
import {
cleanUpOrphanedNotes,
getNotePrefix,
getNotesDir,
getUuidFromNotePath,
initializeGlobalActiveNoteMarkers,
isNotePath,
watchCorrespondingNotes,
} from "./noteUtil";
import { getNotesDir, getUuidFromNotePath } from "./util";
import debounce = require("lodash.debounce");

export type GlobalActiveNoteMarkers = Record<string, Note>;
Expand All @@ -33,7 +35,7 @@ export const activate = (context: vscode.ExtensionContext) => {
const exclude: any = conf.get('files.exclude');
const excludeFiles = {
...exclude,
['.vscode/linenoteplus']: true,
['.vscode/.linenoteplus']: true,
};
conf.update('files.exclude', excludeFiles);

Expand Down Expand Up @@ -163,9 +165,9 @@ export const activate = (context: vscode.ExtensionContext) => {
const placeHolderUuid = short.generate().toString();
const uuid = await vscode.window.showInputBox({
placeHolder: placeHolderUuid,
prompt: 'Enter name for note:',
prompt: 'Enter name for note',
}) || placeHolderUuid;
const marker = `note:${uuid} ${editText} ${removeText}\n`;
const marker = `${getNotePrefix()}${uuid} ${editText} ${removeText}\n`;
const isSuccessful = await editor.edit(edit => {
edit.insert(commentPos, marker);
}, {
Expand Down
13 changes: 6 additions & 7 deletions src/note.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,8 @@ import * as path from "path";
import * as vscode from "vscode";
import { getEditor } from "./editorUtil";
import { globalActiveNoteMarkers } from "./extension";
import { getUuidFromMatch, getWorkspaceRoot } from "./util";
import { getWorkspaceRoot } from "./util";
import { getNoteMarkerRegex, getUuidFromMatch, relNotesDir } from "./noteUtil";

export interface Props {
filePath: string;
Expand All @@ -19,8 +20,6 @@ export interface ConstructorProps {
line: number;
}

export const uuidRegex = /^[A-Za-z0-9]{1,}$/;
export const noteMarkerRegex = /note:\s*[A-Za-z0-9]{1,}\s/gm;
export class Note implements Props {
filePath: string;
notePath: string;
Expand All @@ -30,7 +29,7 @@ export class Note implements Props {
constructor(props: ConstructorProps) {
this.filePath = props.filePath;
this.uuid = props.uuid,
// e.g. $PROJECT_ROOT/.vscode/linenoteplus/73WakrfVbNJBaAmhQtEeDv.md
// e.g. $PROJECT_ROOT/.vscode/.linenoteplus/73WakrfVbNJBaAmhQtEeDv.md
this.notePath = path.join(props.noteDir, this.uuid + '.md');
this.line = props.line;
}
Expand All @@ -48,7 +47,7 @@ export class Note implements Props {

static matchUuids = (text: string): string[] => {
const uuids: string[] = [];
const matches = text.match(noteMarkerRegex);;
const matches = text.match(getNoteMarkerRegex());;
if (!matches) {
return uuids;
}
Expand All @@ -65,7 +64,7 @@ export class Note implements Props {
}

static matchUuid = (lineText: string): string | null => {
const match = lineText.match(noteMarkerRegex);
const match = lineText.match(getNoteMarkerRegex());
if (match) {
const matchText = match[0];
return getUuidFromMatch(matchText);
Expand Down Expand Up @@ -120,7 +119,7 @@ export class Note implements Props {
}

async readAsMarkdown(): Promise<string> {
const wsRoot = getWorkspaceRoot(this.filePath);
const wsRoot = getWorkspaceRoot(this.filePath, relNotesDir);
if (!wsRoot) {
return '';
}
Expand Down
48 changes: 44 additions & 4 deletions src/noteUtil.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,15 +3,55 @@ import * as path from "path";
import * as chokidar from "chokidar";
import {
getIncludedFilePaths,
getNotesDir,
identityDiffArr,
keys,
relNotesDir,
escapeRegex,
} from "./util";
import { Note, uuidRegex } from "./note";
import { Note } from "./note";
import * as vscode from 'vscode';
import { GlobalActiveNoteMarkers, globalActiveNoteMarkers } from "./extension";


export const getNotePrefix = () => {
// note:getNotePrefixNote [Edit] [Remove]
// TODO make configurable
return 'note:';
}

export const getUuidFromMatch = (match: string) => {
return match.split(getNotePrefix())[1].trim();
}

export const getUuidFromNotePath = (notePath: string) => {
const parts = notePath.split(path.sep);
const uuid = parts[parts.length - 1].split('.md')[0];
return uuid;
}

export const relNotesDir = '.vscode/.linenoteplus';
export const getNotesDir = (filePath: string) => {
const workspaceFolders = vscode.workspace.workspaceFolders!;
for (const folder of workspaceFolders) {
const folderPath = folder.uri.fsPath
if (filePath.indexOf(folderPath) != -1) {
const noteDir = path.join(folderPath, relNotesDir);
if (!fs.existsSync(noteDir)) {
fs.mkdirSync(noteDir);
}
return noteDir;
}
}
throw new Error(`Unable to find or create note directory "${relNotesDir}".`);
}

export const uuidRegex = /^[A-Za-z0-9]{1,}$/;
export const getNoteMarkerRegex = () => {
const escapedNotePrefix = escapeRegex(getNotePrefix());
const regexString = `${escapedNotePrefix}[A-Za-z0-9]{1,}\\s`;
const regex = new RegExp(regexString, 'g');
return regex;
}

export const isNotePath = (filePath: string): boolean => {
const noteDir = getNotesDir(filePath);
return filePath.startsWith(noteDir);
Expand Down Expand Up @@ -145,4 +185,4 @@ export const initializeGlobalActiveNoteMarkers = async (
}
}
}
}
}
13 changes: 13 additions & 0 deletions src/test/noteUtil.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import * as assert from "assert";
import { getNoteMarkerRegex } from "../noteUtil";

suite("noteUtil", function() {
suite("getNoteMarkerRegex", function() {
test('produces correct regex', () => {
assert.equal(
getNoteMarkerRegex().toString(),
/note:[A-Za-z0-9]{1,}\s/g.toString()
);
});
});
});
Loading

0 comments on commit 7b24220

Please sign in to comment.