From 12682bfb0b777ea135e56ba68aa7cadcc4bed620 Mon Sep 17 00:00:00 2001 From: Darryl Lawson Date: Wed, 31 Jul 2019 08:57:20 +0930 Subject: [PATCH] Adds support for new note_folder_patterns setting. --- README.md | 44 ++++++++++++++++++++++++---------------- notedown.py | 58 ++++++++++++++++++++++++++++++++++++++--------------- 2 files changed, 69 insertions(+), 33 deletions(-) diff --git a/README.md b/README.md index afeb838..3d06593 100644 --- a/README.md +++ b/README.md @@ -1,25 +1,32 @@ # Notedown for Sublime Text -Notedown lets you use [Sublime Text](http://sublimetext.com/) to manage a collection of notes stored as [Markdown](https://en.wikipedia.org/wiki/Markdown) files. +Notedown lets you use [Sublime Text](http://sublimetext.com/) to manage notes stored as [Markdown](https://en.wikipedia.org/wiki/Markdown) files. -Out of the box, Sublime Text with its built-in Markdown support is already fairly effective for managing notes. However, it lacks one key feature: **linking between notes**. +Out of the box, Sublime Text with its built-in Markdown support, is already pretty good for managing notes. However, it lacks one key feature: **linking between notes**. -Notedown fills this gap. It allows you to link to another note with this syntax: +Notedown fills this gap. It lets you to link to another note with ```text [[Note title]] ``` -Follow a link with **Ctrl + Alt + Left Mouse Button** or **Ctrl + Alt + O** (the *Notedown: Open Link* command). +Follow a link with **Ctrl + Alt + Left Mouse Button** or by positioning the cursor and pressing **Ctrl + Alt + O** or selecting **Notedown: Open Link** in the command palette. -## Feature +## Features -- **Link to other notes** with this syntax: `[[Note title]]`. -- **Note title auto-completion.** Type `[[` and you will be shown a list of notes you can link to. -- **Note renaming.** Change the Markdown Heading on the first line of the note and the note file will automatically be renamed to match. -- **Open a URL** with the same shortcuts you use for opening a note. -- **Note creation.** Click on a link to a note that does not exist and you'll be prompted to create it. -- **Note link validation.** When you save a note, you'll be shown a list of broken note links. +Features provided by Notedown: + +- **Link to another note** with `[[Note title]]`. +- **Note title auto-completion.** Type `[[` and you're shown a list of notes you can link to. +- **Note renaming.** Change the Markdown heading and the note file is automatically renamed to match. +- **Open a URL** conforming to the Markdown syntax with the same shortcuts you use for opening a note. +- **Create a new note** by attempting to open a link to a note that does not exist. +- **Note link validation.** On save, you'll be shown a list of broken note links. + +Note keeping features built into Sublime Text: + +* **Search for a note** with *Goto Anything* (**Command + P** or **Ctrl + P**). +* **Goto a heading within a note** with *Goto Symbol* (**Command + R** or **Ctrl + R**). ## Note links @@ -66,19 +73,22 @@ Any common Markdown file extension -- `.md`, `.mdown`, `.markdown`, or `.markdn` ## Commands -Notedown defines two commands: +Notedown provides these Sublime Text commands: - **notedown_open_link**: Opens the note link or URL under the cursor or mouse selection. - Default mouse map: **Ctrl + Alt + Left Mouse Button** - Default keyboard map: **Ctrl + Alt + O** -- **notedown_lint**: Lints the current file. This is run automatically when a Markdown file is saved. +- **notedown_lint**: Lints the current note. This is run automatically when a note is saved. + +## Settings + +Notedown looks for settings in `Notedown.sublime-settings`. -## User Settings +Notedown supports these settings: -Notedown looks for user settings in `Notedown.sublime-settings`. +- **markdown_extension**: The file extension used when creating new notes. This should not include a leading period (`.`). If not defined, `md` is used. Example: `"markdown_extension": "markdown"`. -Notedown supports a single user setting: +- **note_folder_patterns**: Defines which folders contain *notes* compatible with Notedown. The folder patterns (which may use wildcards compatible with [fnmatch](https://docs.python.org/3/library/fnmatch.html#fnmatch.fnmatch)) are matched against the name of a Markdown file's containing folder to determine if the file should be considered a note. If not defined or an empty list, then all Markdown files are considered to be notes. Example: `"note_folder_patterns": ["Notes"]`. -- **markdown_extension**: Defines the file extension to use when creating new notes. Do not include a leading period (`.`). If not defined, `md` is used. diff --git a/notedown.py b/notedown.py index 5c3b053..52ef1d8 100644 --- a/notedown.py +++ b/notedown.py @@ -36,6 +36,7 @@ anyway. Perhaps tags can be supported one day. """ +import fnmatch import functools import os import re @@ -79,10 +80,10 @@ def wrapper(*args, **kwargs): class _NotedownTextCommand(sublime_plugin.TextCommand): def is_enabled(self): - return _viewing_markdown(self.view) + return _viewing_a_note(self.view) def is_visible(self): - return _viewing_markdown(self.view) + return _viewing_a_note(self.view) class NotedownOpenLinkCommand(_NotedownTextCommand): @@ -185,25 +186,27 @@ def on_pre_close(self, view): pass def on_post_save_async(self, view): - if not _viewing_markdown(view): + if not _viewing_a_note(view): return + renamed = self._reflect_title_in_filename(view) if not renamed: view.run_command('notedown_lint') def on_query_completions(self, view, prefix, locations): + if not _viewing_a_note(view): + return False + if not self._can_show_completions(view, locations): return + file_name = view.file_name() titles = {y for x in _find_notes(view).values() for y, z in x if not os.path.samefile(z, file_name)} return [[x + '\tNote', x + ']]'] for x in sorted(titles)] def _can_show_completions(self, view, locations): - # To show completions, must be a Markdown view, not in raw scope, and - # [[ has been typed. - if not _viewing_markdown(view): - return False + # Show completions if not in raw scope and [[ has been typed. point = locations[0] if view.match_selector(point, 'markup.raw'): return False @@ -318,7 +321,7 @@ def _create_note(title, view): Returns the filename of the new note or None if the user canceled or there was an error. """ - basename = '{}.{}'.format(title, _setting('markdown_extension', + basename = '{}.{}'.format(title, _setting('markdown_extension', str, _DEFAULT_EXTENSION)) text = 'Do you want to create {}?'.format(basename) if not sublime.ok_cancel_dialog(text, 'Create File'): @@ -356,6 +359,37 @@ def _find_link_regions(view): return regions +def _viewing_a_note(view): + if not view.match_selector(0, 'text.html.markdown'): + return False + + note_folder_patterns = _setting('note_folder_patterns', list) + if not note_folder_patterns: + return True + if any(not isinstance(x, str) for x in note_folder_patterns): + _invalid_setting('note_folder_patterns', note_folder_patterns, + '[str, ...]') + return False + + note_folder = os.path.basename(os.path.dirname(view.file_name())) + return any(fnmatch.fnmatch(note_folder, x) for x in note_folder_patterns) + + +def _setting(name, type_, default=None): + value = sublime.load_settings('Notedown.sublime-settings').get(name, + default) + if value is not default and not isinstance(value, type_): + _invalid_setting(name, value, type_) + return default + else: + return value + + +def _invalid_setting(name, value, type_): + sublime.error_message('Invalid Notedown setting "{}":\n\n{!r}\n\n' + 'Must be of type {}.'.format(name, value, type_)) + + def _debug_log(message): if _debug_enabled: _log(message) @@ -366,14 +400,6 @@ def _log(message): sys.stdout.flush() -def _viewing_markdown(view): - return view.match_selector(0, 'text.html.markdown') - - -def _setting(name, default=None): - return sublime.load_settings('Notedown.sublime-settings').get(name, - default) - _debug_enabled = False _notes_cache = {} # {path: (mtime, notes dict)} _link_regions_cache = {} # {buffer id: (change count, regions)}