Skip to content

Instantly share code, notes, and snippets.

@leo60228
Last active November 6, 2025 15:39
Show Gist options
  • Select an option

  • Save leo60228/99d8cbdb061777a4953b2fc3f7d1cafc to your computer and use it in GitHub Desktop.

Select an option

Save leo60228/99d8cbdb061777a4953b2fc3f7d1cafc to your computer and use it in GitHub Desktop.
#!/usr/bin/env nix-shell
#!nix-shell -i python -p "python3.withPackages (p: [ p.pyyaml ])"
import collections.abc
import sys
import json
import yaml
from pathlib import Path
from urllib.parse import urlparse
from urllib.request import urlopen
from yaml.constructor import ConstructorError
from yaml.loader import SafeLoader
from yaml.nodes import MappingNode
class SafeLineLoader(SafeLoader):
def construct_mapping(self, node, deep=False):
if not isinstance(node, MappingNode):
raise ConstructorError(None, None,
"expected a mapping node, but found %s" % node.id,
node.start_mark)
mapping = {}
for key_node, value_node in node.value:
key = self.construct_object(key_node, deep=deep)
if not isinstance(key, collections.abc.Hashable):
raise ConstructorError("while constructing a mapping", node.start_mark,
"found unhashable key", key_node.start_mark)
value = self.construct_object(value_node, deep=deep)
mapping[key] = value
if key in ['Album', 'Track', 'Directory', 'Artist', 'Section']:
mapping[f'{key} Line'] = key_node.start_mark.line
return mapping
def tag(name, file, line, kind, album=None, local=False):
assert '\t' not in name
escaped = line.translate(str.maketrans({'\\': '\\\\', '/': '\\/', '^': '\\^', '$': '\\$'}))
result = f'{name}\t{file}\t/^{escaped}$/;"\t{kind}'
if album is not None:
result += f'\talbum:{album}'
if local:
result += '\tfile:'
print(result)
return result
def multiopen(target):
uri = urlparse(target)
if uri.netloc == "":
return open(target)
else:
return urlopen(target)
with multiopen(sys.argv[1]) as f:
link_data = json.load(f)
data_root = Path(sys.argv[2])
tags = []
for i, album_directory in enumerate(link_data['albumDirectories']):
track_directories = link_data['albumTrackDirectories'][i]
path = data_root / 'album' / f'{album_directory}.yaml'
album_data = path.read_text()
album_lines = album_data.splitlines()
j = 0
tracks = yaml.load_all(album_data, Loader=SafeLineLoader)
album = next(tracks)
if not album.get('Always Reference By Directory'):
tags.append(tag(album['Album'], path, album_lines[album['Album Line']], 'a'))
line = album.get('Directory Line', album['Album Line'])
tags.append(tag(f'album:{album_directory}', path, album_lines[line], 'a', album['Album']))
tracks_by_directory = album.get('Always Reference Tracks By Directory', False)
for track in tracks:
if 'Section' in track:
tags.append(tag(track['Section'], path, album_lines[track['Section Line']], 's', album['Album'], True))
continue
track_directory = track_directories[j]
if not tracks_by_directory and not track.get('Always Reference By Directory', False) and 'Main Release' not in track:
tags.append(tag(track['Track'], path, album_lines[track['Track Line']], 't', album['Album']))
line = track.get('Directory Line', track['Track Line'])
tags.append(tag(f'track:{track_directory}', path, album_lines[line], 't', album['Album']))
j += 1
path = data_root / 'artists.yaml'
artist_data = path.read_text()
artist_lines = artist_data.splitlines()
artists = yaml.load_all(artist_data, Loader=SafeLineLoader)
for artist_directory, artist in zip(link_data['artistDirectories'], artists):
tags.append(tag(artist['Artist'], path, artist_lines[artist['Artist Line']], 'A'))
line = artist.get('Directory Line', artist['Artist Line'])
tags.append(tag(f'artist:{artist_directory}', path, artist_lines[line], 'A'))
tags.sort()
with open('tags', 'w') as f:
for tag in tags:
f.write(f'{tag}\n')
if &filetype !=# "yaml"
finish
endif
silent! fun! s:CompleteThing(findstart, base)
if a:findstart
let line = getline('.')
let link = strridx(line, '[[', col('.'))
if link >= 0
return link + 2
endif
let item = match(line, '^- [''\"]\?\zs')
if item >= 0
return item
endif
return -2
else
if a:base ==# ''
return []
endif
let target = v:null
let line = getline('.')
if line =~ '^- .*'
let context = getline(search('^\(- \)\@!', 'bcnW'))
if context =~ 'Tracks:$'
let target = 't'
elseif context =~ 'Artists:$\|^Contributors:$'
let target = 'A'
endif
endif
let pattern = '^\V' .. escape(a:base, '\/')
if a:base ==# 'track:'
return []
elseif a:base =~ '^\vt(r(a(ck?)?)?)?$'
if target ==# v:null || target ==# 't'
call complete_add('track:')
endif
let pattern = '^\(track:\)\@!\V' .. escape(a:base, '\/')
elseif a:base ==# 'a'
if target ==# 'a' || target ==# v:null
call complete_add('album:')
endif
if target ==# 'A' || target ==# v:null
call complete_add('artist:')
endif
let pattern = '^\(album:\|artist:\)\@!\V' .. escape(a:base, '\/')
elseif a:base =~ '^\val(b(um?)?)?$'
if target ==# v:null || target ==# 'a'
call complete_add('album:')
endif
let pattern = '^\(album:\|artist:\)\@!\V' .. escape(a:base, '\/')
elseif a:base =~ '^\var(t(i(st?)?)?)?$'
if target ==# v:null || target ==# 'A'
call complete_add('artist:')
endif
let pattern = '^\(album:\|artist:\)\@!\V' .. escape(a:base, '\/')
endif
for m in taglist(pattern, expand('%'))
if target ==# v:null || m['kind'] ==# target
if get(m, 'static') && expand('%:p') !=# fnamemodify(m['filename'], ':p')
continue
endif
let candidate = {'word': m['name']}
if has_key(m, 'kind')
let candidate['kind'] = m['kind']
endif
if has_key(m, 'album')
let candidate['info'] = ' ' .. m['album']
endif
call complete_add(candidate)
endif
if complete_check()
return {'words': [], 'refresh': 'always'}
endif
endfor
return []
endif
endfun
silent! fun! s:CompleteProperty(findstart, base)
if a:findstart
return getline('.') =~ ':\|^\s\|^-' ? -2 : 0
else
let line = getline('.')[:col('.') - 2]
if expand('%:t') ==# 'artists.yaml'
let dict = ["Artist: ", "Directory: ", "URLs:\n- ", "Context Notes: ", "Avatar Artwork: ", "Has Avatar: ", "Avatar File Extension: ", "Aliases:\n- ", "Dead URLs:\n- ", "Review Points:\n- "]
else
let dict = ["Track: ", "Track Text: ", "Directory: ", "Suffix Directory: ", "Always Reference By Directory: ", "Main Release: ", "Bandcamp Track ID: ", "Bandcamp Artwork ID: ", "Additional Names:\n- ", "Date First Released: ", "Artist Text: ", "Artist Text In Lists: ", "Artists:\n- ", "Contributors:\n- ", "Count In Artist Totals: ", "Has Cover Art: ", "Has Date: ", "Duration: ", "Color: ", "Needs Lyrics: ", "URLs:\n- ", "Track Artwork: ", "Cover Artists:\n- ", "Cover Art Date: ", "Cover Art File Extension: ", "Cover Art Dimensions: ", "Art Tags:\n- ", "Referenced Artworks:\n- ", "Previous Productions: ", "Referenced Tracks:\n- ", "Sampled Tracks:\n- ", "Additional Files:\n- ", "Sheet Music Files:\n- ", "MIDI Project Files:\n- ", "Lyrics: ", "Commentary: ", "Crediting Sources: ", "Referencing Sources: ", "Franchises:\n- ", "Inherit Franchises: ", "Review Points:\n- "]
endif
for m in matchfuzzy(dict, line)
call complete_add({'word': m, 'abbr': substitute(m, ':\zs.*', '', ''), 'equal': 1})
endfor
return {'words': [], 'refresh': 'always'}
endif
endfun
silent! fun! s:GoToThing()
let curline = line('.')
let curcol = col('.')
let links = matchbufline('%', '\[\[\zs[^\]|]*', curline, curline)
let items = matchbufline('%', '^- [''"]\?\zs.*', curline, curline)
for match in links + items
if curcol < match['byteidx'] || curcol > match['byteidx'] + len(match['text'])
continue
endif
try
execute 'tag' match['text']
catch /^Vim\%((\a\+)\)\=:E426:/
continue
endtry
return
endfor
execute "normal! \<C-]>"
endfun
silent! fun! s:AppendThing()
if getline('.') ==# '---'
normal! k$
else
execute 'normal!' '0/\V\n---\n\|\%$' .. "\<CR>"
call histdel('search', -1)
endif
execute 'normal!' "o\<C-O>D---\<CR>"
startinsert
endfun
silent! fun! s:PrependThing()
if getline('.') ==# '---'
normal! k$
else
execute 'normal!' '0?\V\n---\n' .. "\<CR>"
call histdel('search', -1)
endif
execute 'normal!' "o\<C-O>D---\<CR>"
startinsert
endfun
nnoremap <buffer> <C-]> <Cmd>call <SID>GoToThing()<CR>
nmap <buffer> <C-LeftMouse> <LeftMouse><C-]>
inoremap <buffer> <C-n> <C-x><C-u>
nnoremap <buffer><silent> <LocalLeader>o <Cmd>call <SID>AppendThing()<CR>
nnoremap <buffer><silent> <LocalLeader>O <Cmd>call <SID>PrependThing()<CR>
setlocal iskeyword=@,48-57,_,-,:,192-255
setlocal completefunc=s:CompleteThing
setlocal completeopt+=menu
setlocal indentexpr=
setlocal autoindent
if has('nvim-0.12')
inoremap <buffer><silent><expr> <Tab> pumvisible() ? "\<C-n>" : "\<Tab>"
inoremap <buffer><silent><expr> <S-Tab> pumvisible() ? "\<C-p>" : "\<S-Tab>"
let &l:complete = 'F' .. expand('<SID>') .. 'CompleteThing'
let &l:complete .= ',F' .. expand('<SID>') .. 'CompleteProperty'
setlocal completeopt+=popup
setlocal pumheight=10
setlocal autocomplete
else
setlocal complete=t
endif
if exists(':lua') ==# 2
lua <<EOF
if FzfLua ~= nil then
vim.keymap.set('n', '<LocalLeader>s', function()
path = FzfLua.path.relative_to(vim.api.nvim_buf_get_name(0), vim.uv.cwd())
FzfLua.tags({
search = '^.*?\\t' .. FzfLua.utils.rg_escape(path) .. '\\t.*?\\ts\\t',
no_esc = true,
rg_opts = "--color=never",
})
end, { silent = true, buffer = true })
end
EOF
endif
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment