remove note plugin
This commit is contained in:
parent
0457406122
commit
0c00431eb4
@ -1,6 +1,8 @@
|
||||
deploy_dotfiles.sh
|
||||
.config/**/.git
|
||||
.config/**/.git/**
|
||||
.config/**/notational-fzf-vim
|
||||
.config/**/notational-fzf-vim/**
|
||||
{{ if eq .chezmoi.hostname "taupo" }}
|
||||
.bin
|
||||
.bin/bat
|
||||
|
||||
@ -1,70 +0,0 @@
|
||||
## 2.1.0
|
||||
|
||||
Added more window size management with `g:nv_window_width` and
|
||||
`g:nv_window_direction`. Can now run fullscreen with `:NV!`.
|
||||
|
||||
## 2.0.0
|
||||
|
||||
- Rename `g:nv_directories` to `g:nv_search_paths`. This emphasizes
|
||||
that you can search directories *and* files.
|
||||
- Use `shellescape` instead of `fnameescape` to avoid path issues.
|
||||
- Fix bug in search that would cause it to ignore 1-line long files.
|
||||
|
||||
## 1.1.0
|
||||
|
||||
- Color filenames and line numbers.
|
||||
|
||||
## 1.0.0
|
||||
|
||||
- [rg](https://github.com/BurntSushi/ripgrep) is now required. `ag`
|
||||
will no longer work.
|
||||
- The preview feature has been reworked. Now, the preview window will
|
||||
show several lines of context around the currently selected line.
|
||||
|
||||
## 0.8.0
|
||||
|
||||
- New default for preview window that sensibly sets width. Most users
|
||||
should not need to set this anymore.
|
||||
- Short pathname display no longer shows `./` before filename if it's
|
||||
in the current working directory.
|
||||
|
||||
## 0.7.0
|
||||
|
||||
- You can now restrict your search with arguments passed to `:NV`
|
||||
- Fixed a bug that made preview window too narrow
|
||||
|
||||
## 0.6.0
|
||||
|
||||
- Improve path shortening to display (in decreasing order of
|
||||
priority):
|
||||
- `.`
|
||||
- `..`
|
||||
- `~`
|
||||
- Python 3 is now required for the path shortening script to work.
|
||||
- Key mappings to open files are now customizable.
|
||||
- set `highlight` to use `truecolor` if available and Solarized Dark
|
||||
background.
|
||||
|
||||
## 0.5.0
|
||||
|
||||
- `g:nv_preview_width` is now a percentage. This makes it more useful
|
||||
on small screens, but slightly less useful on large ones without
|
||||
some config.
|
||||
|
||||
## 0.4.0
|
||||
|
||||
- Add support for files in `g:nv_directories`
|
||||
|
||||
## 0.3.0
|
||||
|
||||
- Add (working) short pathnames feature
|
||||
|
||||
## 0.2.0
|
||||
|
||||
- Updated README to include use cases and to be easier to read.
|
||||
|
||||
## 0.1.0
|
||||
|
||||
- Added
|
||||
[`highlight`](http://www.andre-simon.de/doku/highlight/en/highlight.html)
|
||||
as (superior) alternative to `coderay`
|
||||
@ -1,291 +0,0 @@
|
||||
# Notational FZF
|
||||
|
||||
***Loosen the mental blockages to recording information. Scrape away the
|
||||
tartar of convention that handicaps its retrieval.***
|
||||
|
||||
--- [Notational Velocity home page](http://notational.net/)
|
||||
|
||||
Notational Velocity is a note-taking app where searching for a note and
|
||||
creating one are the same operation.
|
||||
|
||||
You search for a query, and if no note matches, it creates a new note
|
||||
with that query as the title.
|
||||
|
||||
## Usage
|
||||
|
||||
See the following GIF or watch this
|
||||
[asciinema](https://asciinema.org/a/oXAsE6lDnywkrSSH5xuOIVQuO):
|
||||
|
||||

|
||||
|
||||
## Installation
|
||||
|
||||
``` {.vim}
|
||||
" with vim-plug
|
||||
Plug 'https://github.com/alok/notational-fzf-vim'
|
||||
```
|
||||
|
||||
## Changes
|
||||
|
||||
Read `CHANGELOG.md`.
|
||||
|
||||
## Description
|
||||
|
||||
Vim is great for writing. But it isn't optimized for note-taking, where
|
||||
you often create lots of little notes and frequently change larger notes
|
||||
in a separate directory from the one you're working in. For years I used
|
||||
[nvALT](http://brettterpstra.com/projects/nvalt/) and whenever I had to
|
||||
do serious editing, I would open the file in Vim.
|
||||
|
||||
But some things about nvALT bugged me.
|
||||
|
||||
- It's not meant for large text files, and opening them will cause it
|
||||
to lag *a lot*.
|
||||
|
||||
- I can't use splits
|
||||
|
||||
- I do most of my work in Vim, so why have another window open,
|
||||
wasting precious screen space with its inferior editing
|
||||
capabilities. Sorry Brett, but nvALT can't match Vim's editing
|
||||
speed.
|
||||
|
||||
- I also disagree with some parts of Notational Velocity's philosophy.
|
||||
|
||||
Plugins like [vim-pad](https://github.com/fmoralesc/vim-pad) didn't do
|
||||
it for me either, because:
|
||||
|
||||
- I don't want to archive my notes. I should be able to just search
|
||||
for them.
|
||||
- I don't want to use the first line as the title since I have notes
|
||||
with duplicated titles in different directories, like `README.md`.
|
||||
- I just want to be able to search a set of directories and create
|
||||
notes in one of them, ***quickly***.
|
||||
|
||||
When [Junegunn](https://github.com/junegunn/) created
|
||||
[`fzf`](https://github.com/junegunn/fzf), I realized that I could have
|
||||
all that, in Vim.
|
||||
|
||||
This plugin allows you to define a list of directories that you want to
|
||||
search. The first directory in the list is used as the main directory,
|
||||
unless you set `g:nv_main_directory`. If you press `control-x` after
|
||||
typing some words, it will use those words as the filename to create a
|
||||
file in the main directory. It will then open that file in a vertical
|
||||
split. If that file already exists, don't worry, it won't overwrite it.
|
||||
This plugin never modifies your files at any point. It can only read,
|
||||
open, and create them.
|
||||
|
||||
You can define relative links, so adding `./docs` and `./notes` will
|
||||
work. Keep in mind that it's relative to your current working directory
|
||||
(as Vim interprets it).
|
||||
|
||||
## Dependencies
|
||||
|
||||
- [`rg`](https://github.com/BurntSushi/ripgrep) is required for its
|
||||
fast search.
|
||||
|
||||
- [`fzf`](https://github.com/junegunn/fzf).
|
||||
|
||||
- `fzf` Vim plugin. Install the Vim plugin that comes with `fzf`,
|
||||
which can be done like so if you use
|
||||
[vim-plug](https://github.com/junegunn/vim-plug).
|
||||
|
||||
``` {.vim}
|
||||
Plug 'junegunn/fzf', { 'dir': '~/.fzf', 'do': './install --all' }
|
||||
```
|
||||
|
||||
- Python 3.5 or higher, for the preview window and filepath
|
||||
shortening.
|
||||
|
||||
## Optional dependencies
|
||||
|
||||
- Pypy 3, for a potential speedup
|
||||
|
||||
## Required Settings
|
||||
|
||||
You have to define a list of directories **or** files (which all must be
|
||||
strings) to search. This setting is named `g:nv_search_paths`.
|
||||
|
||||
Remember that these can be relative links.
|
||||
|
||||
``` {.vim}
|
||||
" example
|
||||
let g:nv_search_paths = ['~/wiki', '~/writing', '~/code', 'docs.md' , './notes.md']
|
||||
```
|
||||
|
||||
## Detailed Usage
|
||||
|
||||
This plugin unites searching and file creation. It defines a single
|
||||
command `:NV`, which can take 0 or more arguments, which are interpreted
|
||||
as regexes.
|
||||
|
||||
Type `:NV` or bind it to a mapping to bring up a fuzzy search menu. Type
|
||||
in your search terms and it will fuzzy search for them. Adding an
|
||||
exclamation mark to the command (`:NV!`), will run it fullscreen.
|
||||
|
||||
You can type `:NV` to see all results, and then filter them with FZF.
|
||||
You can type `:NV python` to restrict your initial search to lines that
|
||||
contain the phrase `python`. `:NV [0-9] [0-9]` will find all numbers
|
||||
separated by a space. You know, regexes.
|
||||
|
||||
It does not search in a fully fuzzy fashion because that's less useful
|
||||
for prose. It looks for full words, but they don't have to be next to
|
||||
each other, just on the same line. You can use the arrow keys or `c-p`
|
||||
and `c-n` to scroll through the search results, and then hit one of
|
||||
these keys to open up a file:
|
||||
|
||||
Note that the following options can be customized.
|
||||
|
||||
- `c-x`: Use search string as filename and open in vertical split.
|
||||
- `c-v`: Open in vertical split
|
||||
- `c-s`: Open in horizontal split
|
||||
- `c-t`: Open in new tab
|
||||
- `c-y`: Yank the selected filenames
|
||||
- `<Enter>`: Open highlighted search result in current buffer
|
||||
|
||||
The lines around the selected file will be visible in a preview window.
|
||||
|
||||
## Mappings
|
||||
|
||||
This plugin only defines a command `:NV`, and if you want a mapping for
|
||||
it, you can define it yourself. This is intentionally not done by
|
||||
default. You should use whatever mapping(s) work best for you.
|
||||
|
||||
For example,
|
||||
|
||||
``` {.vim}
|
||||
nnoremap <silent> <c-s> :NV<CR>
|
||||
```
|
||||
|
||||
## Optional Settings and Their Defaults
|
||||
|
||||
You can display the full path by setting `g:nv_use_short_pathnames = 0`.
|
||||
|
||||
You can toggle displaying the preview window by pressing `alt-p`. This
|
||||
is handy on smaller screens. If you don't want to show the preview by
|
||||
default, set `g:nv_show_preview = 0`.
|
||||
|
||||
``` {.vim}
|
||||
" String. Set to '' (the empty string) if you don't want an extension appended by default.
|
||||
" Don't forget the dot, unless you don't want one.
|
||||
let g:nv_default_extension = '.md'
|
||||
|
||||
" String. Default is first directory found in `g:nv_search_paths`. Error thrown
|
||||
"if no directory found and g:nv_main_directory is not specified
|
||||
"let g:nv_main_directory = g:nv_main_directory or (first directory in g:nv_search_paths)
|
||||
|
||||
" Dictionary with string keys and values. Must be in the form 'ctrl-KEY':
|
||||
" 'command' or 'alt-KEY' : 'command'. See examples below.
|
||||
let g:nv_keymap = {
|
||||
\ 'ctrl-s': 'split ',
|
||||
\ 'ctrl-v': 'vertical split ',
|
||||
\ 'ctrl-t': 'tabedit ',
|
||||
\ })
|
||||
|
||||
" String. Must be in the form 'ctrl-KEY' or 'alt-KEY'
|
||||
let g:nv_create_note_key = 'ctrl-x'
|
||||
|
||||
" String. Controls how new note window is created.
|
||||
let g:nv_create_note_window = 'vertical split'
|
||||
|
||||
" Boolean. Show preview. Set by default. Pressing Alt-p in FZF will toggle this for the current search.
|
||||
let g:nv_show_preview = 1
|
||||
|
||||
" Boolean. Respect .*ignore files in or above nv_search_paths. Set by default.
|
||||
let g:nv_use_ignore_files = 1
|
||||
|
||||
" Boolean. Include hidden files and folders in search. Disabled by default.
|
||||
let g:nv_include_hidden = 0
|
||||
|
||||
" Boolean. Wrap text in preview window.
|
||||
let g:nv_wrap_preview_text = 1
|
||||
|
||||
" String. Width of window as a percentage of screen's width.
|
||||
let g:nv_window_width = '40%'
|
||||
|
||||
" String. Determines where the window is. Valid options are: 'right', 'left', 'up', 'down'.
|
||||
let g:nv_window_direction = 'down'
|
||||
|
||||
" String. Command to open the window (e.g. `vertical` `aboveleft` `30new` `call my_function()`).
|
||||
let g:nv_window_command = 'call my_function()'
|
||||
|
||||
" Float. Width of preview window as a percentage of screen's width. 50% by default.
|
||||
let g:nv_preview_width = 50
|
||||
|
||||
" String. Determines where the preview window is. Valid options are: 'right', 'left', 'up', 'down'.
|
||||
let g:nv_preview_direction = 'right'
|
||||
|
||||
" String. Yanks the selected filenames to the default register.
|
||||
let g:nv_yank_key = 'ctrl-y'
|
||||
|
||||
" String. Separator used between yanked filenames.
|
||||
let g:nv_yank_separator = "\n"
|
||||
|
||||
" Boolean. If set, will truncate each path element to a single character. If
|
||||
" you have colons in your pathname, this will fail. Set by default.
|
||||
let g:nv_use_short_pathnames = 1
|
||||
|
||||
"List of Strings. Shell glob patterns. Ignore all filenames that match any of
|
||||
" the patterns.
|
||||
let g:nv_ignore_pattern = ['summarize-*', 'misc*']
|
||||
|
||||
" List of Strings. Key mappings like above in case you want to define your own
|
||||
" handler function. Most users won't want to set this to anything.
|
||||
|
||||
let g:nv_expect_keys = []
|
||||
```
|
||||
|
||||
You can also define your own handler function, in case you don't like
|
||||
how this plugin handles input but like how it wraps everything else. It
|
||||
*must* be called `NV_note_handler`.
|
||||
|
||||
## Potential Use Cases
|
||||
|
||||
- Add `~/notes` and `~/wiki` so your notes are only one key binding
|
||||
away.
|
||||
- Add relative links like `./notes`, `./doc`, etc. to
|
||||
`g:nv_search_paths` so you can always see/update the documentation
|
||||
of your current project and keep up-to-date personal notes.
|
||||
|
||||
## Philosophy
|
||||
|
||||
To quote [scrod](https://github.com/scrod/nv/issues/22),
|
||||
|
||||
> The reasoning behind Notational Velocity's present lack of
|
||||
> multi-database support is that storing notes in separate databases
|
||||
> would 1) Require the same kinds of decisions that
|
||||
> category/folder-based organizers force upon their users (e.g., "Is
|
||||
> this note going to be work-specific or home-specific?"), and 2) Defeat
|
||||
> the point of instantaneous searching by requiring, ultimately, the
|
||||
> user to repeat each search for every database in use.
|
||||
|
||||
- By providing a default directory, we offer (one) fix to the first
|
||||
issue.
|
||||
|
||||
- By searching the whole set of directories simultaneously, we handle
|
||||
the second.
|
||||
|
||||
It also handles Notational Velocity's issue with multiple databases.
|
||||
UNIX does not allow repeated filenames in the same folder, but often the
|
||||
parent folder provides context, like in `workout/TODO.md` and
|
||||
`coding/TODO.md`.
|
||||
|
||||
This plug-in attempts to abstract the operation of note-taking over
|
||||
*all* the notes you take, with priority given to one main notes
|
||||
directory.
|
||||
|
||||
## Caveat Emptor
|
||||
|
||||
- This plugin is just a wrapper over FZF that can view directories and
|
||||
open/create files. That's all it's ever meant to be. Anything else
|
||||
would be put into a separate plugin.
|
||||
|
||||
## Feedback
|
||||
|
||||
Is ***always*** welcome. If you have any ideas or issues, let me know
|
||||
and I'll try to address them. Not all will be implemented, but if they
|
||||
fit into the philosophy of this plugin or seem really useful, I'll do my
|
||||
best.
|
||||
|
||||
## License
|
||||
|
||||
Apache 2
|
||||
@ -1,12 +0,0 @@
|
||||
## Checklist
|
||||
|
||||
<!-- Update to the latest version of this plugin *first*. -->
|
||||
|
||||
- [ ] I updated.
|
||||
|
||||
<!-- If your issue is about changing how notes are handled once selected, search for `NV_note_handler` in `README.md`-->
|
||||
|
||||
- [ ] `NV_note_handler` cannot fix my issue.
|
||||
|
||||
## Summary of Problem
|
||||
|
||||
@ -1,4 +0,0 @@
|
||||
notes.md
|
||||
tags.lock
|
||||
usage.frames.json
|
||||
tags.temp
|
||||
@ -1,33 +0,0 @@
|
||||
#!/usr/bin/env python3
|
||||
# -*- coding: utf-8 -*-
|
||||
"""Colorize the current line in the preview window in bold red."""
|
||||
|
||||
import os
|
||||
import os.path as path
|
||||
import shutil
|
||||
import sys
|
||||
|
||||
line = int(sys.argv[1])
|
||||
file = sys.argv[2]
|
||||
|
||||
# Use a large default for width since the extra doesn't get displayed anyway
|
||||
width = max(1, shutil.get_terminal_size().lines // 2)
|
||||
end_width = 200
|
||||
|
||||
# file numbers start at 1
|
||||
beginning = max(1, line - width)
|
||||
end = line + end_width
|
||||
|
||||
# ANSI escape sequences for coloring matched line
|
||||
RED = "\033[1;31m"
|
||||
RESET = "\033[0;0m"
|
||||
BOLD = "\033[;1m"
|
||||
|
||||
if __name__ == "__main__":
|
||||
with open(path.normpath(file)) as f:
|
||||
for linenum, line_content in enumerate(f, start=1):
|
||||
if beginning <= linenum <= end:
|
||||
if linenum == line:
|
||||
print(BOLD + RED + line_content.rstrip() + RESET)
|
||||
else:
|
||||
print(line_content.rstrip())
|
||||
@ -1,117 +0,0 @@
|
||||
#!/usr/bin/env pypy3
|
||||
# encoding: utf-8
|
||||
|
||||
# Supposedly, importing so that you don't need dots in names speeds up a
|
||||
# script, and the point of this one is to run fast.
|
||||
|
||||
import platform
|
||||
from os import pardir
|
||||
from os.path import abspath, expanduser, join, sep, split, splitdrive
|
||||
from pathlib import PurePath
|
||||
from sys import stdin
|
||||
|
||||
|
||||
# These are floated to the top so they aren't recalculated every loop. The
|
||||
# most restrictive replacements should come earlier.
|
||||
REPLACEMENTS = ("", pardir, "~")
|
||||
old_paths = [abspath(expanduser(replacement)) for replacement in REPLACEMENTS]
|
||||
IS_WINDOWS = platform.system().lower() == "windows"
|
||||
|
||||
|
||||
def prettyprint_path(path: str, old_path: str, replacement: str) -> str:
|
||||
# Pretty print the path prefix
|
||||
path = path.replace(old_path, replacement, 1)
|
||||
# Truncate the rest of the path to a single character.
|
||||
short_path = join(replacement, *[x[0] for x in PurePath(path).parts[1:]])
|
||||
return short_path
|
||||
|
||||
|
||||
def shorten(path: str):
|
||||
"""Returns 2 strings, the shortened parent directory and the filename."""
|
||||
# We don't want to shorten the filename, just its parent directory, so we
|
||||
# `split()` and just shorten `path`.
|
||||
path, filename = split(path)
|
||||
|
||||
# use empty replacement for current directory. it expands correctly
|
||||
|
||||
for replacement, old_path in zip(REPLACEMENTS, old_paths):
|
||||
if path.startswith(old_path):
|
||||
short_path = prettyprint_path(path, old_path, replacement)
|
||||
# to avoid multiple replacements
|
||||
break
|
||||
|
||||
# If no replacement was found, shorten the entire path.
|
||||
else:
|
||||
short_path = join(*[x[0] for x in PurePath(path).parts])
|
||||
|
||||
return short_path, filename
|
||||
|
||||
|
||||
GREEN = "\033[32m"
|
||||
PURPLE = "\033[35m" # looks pink to me
|
||||
CYAN = "\033[36m"
|
||||
|
||||
RESET = "\033[0m"
|
||||
|
||||
# RED = '\033[31m'
|
||||
# BLUE = '\033[34m'
|
||||
# LIGHTRED = '\033[91m'
|
||||
# YELLOW = '\033[93m'
|
||||
# LIGHTBLUE = '\033[94m'
|
||||
# LIGHTCYAN = '\033[96m'
|
||||
|
||||
|
||||
def color(line, color):
|
||||
return color + line + RESET
|
||||
|
||||
|
||||
def process_line(line: str) -> str:
|
||||
# Expected format is colon separated `name:line number:contents`
|
||||
|
||||
if IS_WINDOWS:
|
||||
# Windows paths may contain a colon, e.g. C:\Windows\ which messes up the split
|
||||
# splitdrive(string) results in the following:
|
||||
# Windows drive letter, e.g. C:\Windows\Folder\Foo.txt -> ('C', '\Windows\Folder\Foo.txt')
|
||||
# Windows UNC path, e.g. \\Server\Share\Folder\Foo.txt -> ('\\Server\Share', '\Folder\Foo.txt')
|
||||
# *nix, e.g. /any/path/to/file.txt -> ('', '/any/path/to/file.txt')
|
||||
_, line = splitdrive(line) # Toss the drive letter since it's not necessary.
|
||||
filename, linenum, contents = line.split(sep=":", maxsplit=2)
|
||||
|
||||
# Drop trailing newline.
|
||||
contents = contents.rstrip()
|
||||
|
||||
# Normalize path for further processing.
|
||||
if not IS_WINDOWS:
|
||||
# This prepends cwd in Windows which is unnecessary.
|
||||
filename = abspath(filename)
|
||||
|
||||
shortened_parent, basename = shorten(filename)
|
||||
# The conditional is to avoid a leading slash if the parent is replaced
|
||||
# with an empty directory. The slash is manually colored because otherwise
|
||||
# `os.path.join` won't do it.
|
||||
if shortened_parent:
|
||||
colored_short_name = color(shortened_parent + sep, PURPLE) + color(
|
||||
basename, CYAN
|
||||
)
|
||||
else:
|
||||
colored_short_name = color(basename, CYAN)
|
||||
|
||||
# Format is: long form, line number, short form, line number, rest of line. This is so Vim can process it.
|
||||
formatted_line = ":".join(
|
||||
[
|
||||
color(filename, CYAN),
|
||||
color(linenum, GREEN),
|
||||
colored_short_name,
|
||||
color(linenum, GREEN),
|
||||
contents,
|
||||
]
|
||||
)
|
||||
return formatted_line
|
||||
|
||||
# We print the long and short forms, and one form is picked in the Vim script that uses this.
|
||||
# print(formatted_line)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
for line in stdin:
|
||||
print(process_line(line))
|
||||
@ -1,263 +0,0 @@
|
||||
"============================== Utility functions =============================
|
||||
|
||||
" XXX: fnameescape vs. shellescape: for vim's consumption vs. the shell's
|
||||
" consumption
|
||||
|
||||
function! s:single_quote(str)
|
||||
return "'" . a:str . "'"
|
||||
endfunction
|
||||
|
||||
"============================= Dependencies ================================
|
||||
|
||||
if !executable('rg')
|
||||
echoerr '`rg` is not installed. See https://github.com/BurntSushi/ripgrep for installation instructions.'
|
||||
finish
|
||||
endif
|
||||
|
||||
"============================== User settings ==============================
|
||||
|
||||
|
||||
if !exists('g:nv_search_paths')
|
||||
|
||||
if exists('g:nv_directories')
|
||||
echoerr '`g:nv_directories` has been renamed `g:nv_search_paths`. Please update your config files.'
|
||||
else
|
||||
echoerr '`g:nv_search_paths` is not defined.'
|
||||
endif
|
||||
|
||||
finish
|
||||
|
||||
endif
|
||||
|
||||
let s:window_direction = get(g:, 'nv_window_direction', 'down')
|
||||
let s:window_width = get(g:, 'nv_window_width', '40%')
|
||||
let s:window_command = get(g:, 'nv_window_command', '')
|
||||
|
||||
let s:ext = get(g:, 'nv_default_extension', '.md')
|
||||
|
||||
" Valid options are ['up', 'down', 'right', 'left']. Default is 'right'. No colon for
|
||||
" this command since it's first in the list.
|
||||
let s:preview_direction = get(g:, 'nv_preview_direction', 'right')
|
||||
|
||||
let s:wrap_text = get(g:, 'nv_wrap_preview_text', 0) ? 'wrap' : ''
|
||||
|
||||
" Show preview unless user set it to be hidden
|
||||
let s:show_preview = get(g:, 'nv_show_preview', 1) ? '' : 'hidden'
|
||||
|
||||
" Respect .*ignore files unless user has chosen not to
|
||||
let s:use_ignore_files = get(g:, 'nv_use_ignore_files', 1) ? '' : '--no-ignore'
|
||||
|
||||
" Skip hidden files and folders unless user chooses to include them
|
||||
let s:include_hidden = get(g:, 'nv_include_hidden', 0) ? '--hidden' : ''
|
||||
|
||||
" How wide to make preview window. 72 characters is default.
|
||||
let s:preview_width = exists('g:nv_preview_width') ? string(float2nr(str2float(g:nv_preview_width) / 100.0 * &columns)) : ''
|
||||
|
||||
" Expand all directories and escape metacharacters to avoid issues later.
|
||||
let s:search_paths = map(copy(g:nv_search_paths), 'expand(v:val)')
|
||||
|
||||
" Separator for yanked files
|
||||
let s:yank_separator = get(g:, 'nv_yank_separator', "\n")
|
||||
|
||||
"=========================== Windows Overrides ============================
|
||||
|
||||
if has('win64') || has('win32')
|
||||
let s:null_path = 'NUL'
|
||||
let s:command = ''
|
||||
else
|
||||
let s:null_path = '/dev/null'
|
||||
let s:command = 'command'
|
||||
endif
|
||||
|
||||
" The `exists()` check needs to be first in case the main directory is not
|
||||
" part of `g:nv_search_paths`.
|
||||
if exists('g:nv_main_directory')
|
||||
let s:main_dir = g:nv_main_directory
|
||||
else
|
||||
for path in s:search_paths
|
||||
if isdirectory(path)
|
||||
let s:main_dir = path
|
||||
break
|
||||
endif
|
||||
endfor
|
||||
|
||||
" this awkward bit of code is to get around the lack of a for-else
|
||||
" loop in vim
|
||||
if !exists('s:main_dir')
|
||||
echomsg 'no directories found in `g:nv_search_paths`'
|
||||
finish
|
||||
endif
|
||||
endif
|
||||
|
||||
let s:search_path_str = join(map(copy(s:search_paths), 'shellescape(v:val)'))
|
||||
|
||||
"=========================== Keymap ========================================
|
||||
|
||||
let s:create_note_key = get(g:, 'nv_create_note_key', 'ctrl-x')
|
||||
let s:yank_key = get(g:, 'nv_yank_key', 'ctrl-y')
|
||||
let s:create_note_window = get(g:, 'nv_create_note_window', 'vertical split ')
|
||||
|
||||
let s:keymap = get(g:, 'nv_keymap',
|
||||
\ {'ctrl-s': 'split',
|
||||
\ 'ctrl-v': 'vertical split',
|
||||
\ 'ctrl-t': 'tabedit',
|
||||
\ })
|
||||
|
||||
" Use `extend` in case user overrides default keys
|
||||
let s:keymap = extend(s:keymap, {
|
||||
\ s:create_note_key : s:create_note_window,
|
||||
\ })
|
||||
|
||||
" FZF expects a comma separated string.
|
||||
let s:expect_keys = join(keys(s:keymap) + get(g:, 'nv_expect_keys', []) + [s:yank_key], ',')
|
||||
|
||||
"================================ Yank string ==============================
|
||||
|
||||
function! s:yank_to_register(data)
|
||||
let @" = a:data
|
||||
silent! let @* = a:data
|
||||
silent! let @+ = a:data
|
||||
endfunction
|
||||
|
||||
"================================ Short Pathnames ==========================
|
||||
|
||||
let s:use_short_pathnames = get(g:, 'nv_use_short_pathnames', 1)
|
||||
|
||||
" Python 3 is required for this to work
|
||||
let s:python_executable = executable('pypy3') ? 'pypy3' : get(g:, 'python3_host_prog', 'python3')
|
||||
let s:highlight_path_expr = join([s:python_executable , '-S',expand('<sfile>:p:h:h') . '/print_lines.py' , '{2} {1} ', '2>' . s:null_path,])
|
||||
|
||||
if s:use_short_pathnames
|
||||
let s:format_path_expr = join([' | ', s:python_executable, '-S', shellescape(expand('<sfile>:p:h:h') . '/shorten_path_for_notational_fzf.py'),])
|
||||
" After piping through the Python script, our format is
|
||||
" filename:linum:shortname:linenum:contents, so we start at index 3 to
|
||||
" avoid displaying the long pathname
|
||||
" We skip index 4 to avoid showing line numbers
|
||||
let s:display_start_index = '3,5..'
|
||||
else
|
||||
let s:format_path_expr = ''
|
||||
" Since we don't pipe through the python script, our data format is
|
||||
" filename:linenum:contents, so we start at 1.
|
||||
let s:display_start_index = '1..'
|
||||
endif
|
||||
|
||||
"============================ Ignore patterns ==============================
|
||||
|
||||
function! s:ignore_list_to_str(pattern)
|
||||
"list -> space separated string of glob patterns.
|
||||
" Format to ignore a pattern.
|
||||
" XXX The leading space matters.
|
||||
let l:glob_fmt = ' --glob !'
|
||||
return l:glob_fmt . join(map(copy(a:pattern), 's:single_quote(v:val)'), l:glob_fmt) " prepend glob format string so the first pattern is ignored too.
|
||||
endfunction
|
||||
|
||||
let s:nv_ignore_pattern = exists('g:nv_ignore_pattern') ? s:ignore_list_to_str(g:nv_ignore_pattern) : ''
|
||||
|
||||
"============================== Handler Function ===========================
|
||||
|
||||
function! s:handler(lines) abort
|
||||
" exit if empty
|
||||
if a:lines == [] || a:lines == ['','','']
|
||||
return
|
||||
endif
|
||||
" Expect at least 2 elements, `query` and `keypress`, which may be empty
|
||||
" strings.
|
||||
let query = a:lines[0]
|
||||
let keypress = a:lines[1]
|
||||
" `edit` is fallback in case something goes wrong
|
||||
let cmd = get(s:keymap, keypress, 'edit')
|
||||
" Preprocess candidates here. expect lines to have fmt
|
||||
" filename:linenum:content
|
||||
|
||||
" Handle creating note.
|
||||
if keypress ==? s:create_note_key
|
||||
let candidates = [fnameescape(s:main_dir . '/' . query . s:ext)]
|
||||
elseif keypress ==? s:yank_key
|
||||
let pat = '\v(.{-}):\d+:'
|
||||
let hashes = join(filter(map(copy(a:lines[2:]), 'matchlist(v:val, pat)[1]'), 'len(v:val)'), s:yank_separator)
|
||||
return s:yank_to_register(hashes)
|
||||
else
|
||||
let filenames = a:lines[2:]
|
||||
let candidates = []
|
||||
for filename in filenames
|
||||
" Don't forget trailing space in replacement.
|
||||
let linenum = substitute(filename, '\v.{-}:(\d+):.*$', '+\1 ', '')
|
||||
let name = substitute(filename, '\v(.{-}):\d+:.*$', '\1', '')
|
||||
" fnameescape instead of shellescape because the file is consumed
|
||||
" by vim rather than the shell
|
||||
call add(candidates, linenum . fnameescape(name))
|
||||
endfor
|
||||
endif
|
||||
|
||||
for candidate in candidates
|
||||
execute join([cmd, candidate])
|
||||
endfor
|
||||
|
||||
endfunction
|
||||
|
||||
" If the file you're looking for is empty, then why does it even exist? It's a
|
||||
" note. Just type its name. Hence we ignore lines with only space characters,
|
||||
" and use the "\S" regex.
|
||||
|
||||
" Use a big ugly option list. The '.. ' is because fzf wants a term of the
|
||||
" form 'N.. ' where N is a number.
|
||||
|
||||
" Use `command` in front of 'rg' to ignore aliases.
|
||||
" The `' "\S" '` is so that the backslash itself doesn't require escaping.
|
||||
" g:search_paths is already shell escaped, so we don't do it again
|
||||
command! -nargs=* -bang NV
|
||||
\ call fzf#run(
|
||||
\ fzf#wrap({
|
||||
\ 'sink*': function(exists('*NV_note_handler') ? 'NV_note_handler' : '<sid>handler'),
|
||||
\ 'window': s:window_command,
|
||||
\ 'source': join([
|
||||
\ s:command,
|
||||
\ 'rg',
|
||||
\ '--follow',
|
||||
\ s:use_ignore_files,
|
||||
\ '--smart-case',
|
||||
\ s:include_hidden,
|
||||
\ '--line-number',
|
||||
\ '--color never',
|
||||
\ '--no-messages',
|
||||
\ s:nv_ignore_pattern,
|
||||
\ '--no-heading',
|
||||
\ '--with-filename',
|
||||
\ ((<q-args> is '') ?
|
||||
\ '"\S"' :
|
||||
\ shellescape(<q-args>)),
|
||||
\ s:search_path_str,
|
||||
\ s:format_path_expr,
|
||||
\ '2>' . s:null_path,
|
||||
\ ]),
|
||||
\ s:window_direction: s:window_width,
|
||||
\ 'options': join([
|
||||
\ '--print-query',
|
||||
\ '--ansi',
|
||||
\ '--multi',
|
||||
\ '--exact',
|
||||
\ '--inline-info',
|
||||
\ '--delimiter=":"',
|
||||
\ '--with-nth=' . s:display_start_index ,
|
||||
\ '--tiebreak=' . 'length,begin' ,
|
||||
\ '--expect=' . s:expect_keys ,
|
||||
\ '--bind=' . join([
|
||||
\ 'alt-a:select-all',
|
||||
\ 'alt-q:deselect-all',
|
||||
\ 'alt-p:toggle-preview',
|
||||
\ 'alt-u:page-up',
|
||||
\ 'alt-d:page-down',
|
||||
\ 'ctrl-w:backward-kill-word',
|
||||
\ ], ','),
|
||||
\ '--preview=' . shellescape(s:highlight_path_expr) ,
|
||||
\ '--preview-window=' . join(filter(copy([
|
||||
\ s:preview_direction,
|
||||
\ s:preview_width,
|
||||
\ s:wrap_text,
|
||||
\ s:show_preview,
|
||||
\ ]),
|
||||
\ 'v:val != "" ')
|
||||
\ ,':')
|
||||
\ ])},<bang>0))
|
||||
|
||||
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 1.3 MiB |
Loading…
x
Reference in New Issue
Block a user