init
This commit is contained in:
commit
5e1b2ac657
26 changed files with 393 additions and 0 deletions
9
bash/last/last.sh
Executable file
9
bash/last/last.sh
Executable file
|
|
@ -0,0 +1,9 @@
|
||||||
|
# Get the last file name of any numbered series of text files.
|
||||||
|
|
||||||
|
# file format:
|
||||||
|
# in regex terms:
|
||||||
|
# [0-9]+\.[.*\.]*md|txt
|
||||||
|
# in plain terms:
|
||||||
|
# [leading numbers with consistent width].[optional string descriptor and . separator][md|txt]
|
||||||
|
|
||||||
|
ls | egrep '^\d.*\.md|txt' | tail -n 1
|
||||||
0
bash/last/test/001.md
Executable file
0
bash/last/test/001.md
Executable file
0
bash/last/test/002.blah.md
Executable file
0
bash/last/test/002.blah.md
Executable file
0
bash/last/test/004.foo.md
Executable file
0
bash/last/test/004.foo.md
Executable file
0
bash/last/test/005.md
Executable file
0
bash/last/test/005.md
Executable file
0
bash/last/test/009.boo.md
Executable file
0
bash/last/test/009.boo.md
Executable file
0
bash/last/test/098.baa.md
Executable file
0
bash/last/test/098.baa.md
Executable file
0
bash/last/test/099.poo.md
Executable file
0
bash/last/test/099.poo.md
Executable file
23
bash/mdcat/mdcat.sh
Executable file
23
bash/mdcat/mdcat.sh
Executable file
|
|
@ -0,0 +1,23 @@
|
||||||
|
# cat for Markdown in my ultralight writing database
|
||||||
|
# wherein concatenated filed need a "\n---\n\n" between them.
|
||||||
|
|
||||||
|
#############################################################################
|
||||||
|
# cat with file headers | replace with section string | remove first instance
|
||||||
|
|
||||||
|
# NOTE: only need to add one newline, because the header inserted by tail
|
||||||
|
# implicitly adds two : \n==> foo <==\n
|
||||||
|
tail -n +1 "$@" | sed 's/^==> .* <==$/---\n/g' | tail -n +3
|
||||||
|
|
||||||
|
|
||||||
|
##############################
|
||||||
|
# failed approaches
|
||||||
|
|
||||||
|
# find . -type f -name "$@" -exec cat {} \; -printf "\n---\n\n"
|
||||||
|
|
||||||
|
# this leaves one trailing, could cat the whole thing and then cut the tail off
|
||||||
|
# MDCATALL=`for i in "$@";
|
||||||
|
# do
|
||||||
|
# cat $i
|
||||||
|
# echo '\n---\n\n'
|
||||||
|
# done`
|
||||||
|
# echo $MDCATALL | head -n +2
|
||||||
12
bash/next/args.sh
Executable file
12
bash/next/args.sh
Executable file
|
|
@ -0,0 +1,12 @@
|
||||||
|
# why can't i use bash if statement, before appending an empty arg string?
|
||||||
|
|
||||||
|
last=`ls | egrep '^\d.*\.md|txt' | tail -n 1`
|
||||||
|
|
||||||
|
if ($* != "")
|
||||||
|
last=last + $*;
|
||||||
|
|
||||||
|
awk '
|
||||||
|
{
|
||||||
|
print $0
|
||||||
|
}
|
||||||
|
END {print NR}' last
|
||||||
2
bash/next/emacs_script.sh
Executable file
2
bash/next/emacs_script.sh
Executable file
|
|
@ -0,0 +1,2 @@
|
||||||
|
# emacs --debug-init blah
|
||||||
|
emacs `ls | grep '^\d' | tail -n 1`
|
||||||
113
bash/next/next.sh
Executable file
113
bash/next/next.sh
Executable file
|
|
@ -0,0 +1,113 @@
|
||||||
|
# Get the file name in any numbered series of text files and open with emacs
|
||||||
|
|
||||||
|
# Usage:
|
||||||
|
# $ . next [descriptor]
|
||||||
|
|
||||||
|
# Handles an optional string descriptor. Like this:
|
||||||
|
# $ ls
|
||||||
|
# 011.blah.md
|
||||||
|
# $ . next foo
|
||||||
|
# 012.foo.md
|
||||||
|
|
||||||
|
# File format:
|
||||||
|
# in regex terms:
|
||||||
|
# [0-9]+\.[.*\.]*md|txt
|
||||||
|
# in plain terms:
|
||||||
|
# [leadings numbers with consistent width].[optional string descriptor and . separator][md|txt]
|
||||||
|
|
||||||
|
# what this does:
|
||||||
|
# ls | grep [regex for number.*.md] | get last | awk script to increment the digits, preserve the zero prefix, add string descriptor if supplied, and add back extension
|
||||||
|
|
||||||
|
# Note the egrep '^\d.*\.md|txt' (matches whole string) to account for an optional string between the initial number and the file extension. As in '435.blah.md'.
|
||||||
|
|
||||||
|
# old version, relied on python, which didn't handle leading zeros properly, but treated them as binary:
|
||||||
|
# ls | grep '\d.*\.md' | tail -n 1 | sed s/'\..*md'// | sed s/.*/'print & + 1'/ | python - | sed s/.*/'&.md/'
|
||||||
|
|
||||||
|
# BUGS
|
||||||
|
|
||||||
|
# 1. Emacs won't accept piped input as a file name. I'd rather keep this as a separate utility, which only printed the right filename, and then use an alias to pipe the filename to emacs, or invoke it manually.
|
||||||
|
|
||||||
|
# A.
|
||||||
|
# What I want, is this syntax:
|
||||||
|
# next [optional arg]
|
||||||
|
# To both get the file and open emacs with it.
|
||||||
|
|
||||||
|
# B.
|
||||||
|
# But this doesn't work:
|
||||||
|
# next | emacs
|
||||||
|
# Because it sees the stdin the pipe wants to feed it as a substitute for the tty in the new session, rather than as input for startup only, i.e. the filename.
|
||||||
|
|
||||||
|
# C.
|
||||||
|
# Wrapping the whole shell command here works, like this:
|
||||||
|
# emacs `ls | grep ...`
|
||||||
|
|
||||||
|
# But emacs doesn't like being run inside a child level shell, because it can't load .emacs properly. So you must run this file within the current shell using ".", like this:
|
||||||
|
# . next
|
||||||
|
# . next foo
|
||||||
|
|
||||||
|
# D.
|
||||||
|
# This does not work, because .profile must be executed, meaning that the "" expression is peeked by the shell:
|
||||||
|
# alias next="emacs `next.sh $1`"
|
||||||
|
|
||||||
|
# E.
|
||||||
|
# This does not work either, because the arg never gets filled out when evoked:
|
||||||
|
# alias next='emacs `next.sh $1`'
|
||||||
|
|
||||||
|
# F.
|
||||||
|
# This works and is the current solution:
|
||||||
|
# alias next='. next.sh'
|
||||||
|
|
||||||
|
# Which relies on 2 somewhat obscured facts:
|
||||||
|
# 1. This script calls emacs itself, wrapping the real work in ``
|
||||||
|
# 2. The alias is a simple substitution, which fortunately seems to happen before args are processed by the shell, meaning that the shell sees: ". next.sh arg"
|
||||||
|
# 3. NOTE: the symbolic link in the PATH should not be simply "next", because it
|
||||||
|
# may in certain situations conflict with the alias. The link should be "next.sh" -> ~/config/..
|
||||||
|
# 4. NOTE: I use 'e' rather than 'emacs', to use my clever emacs/emacsclient function.
|
||||||
|
|
||||||
|
e `
|
||||||
|
|
||||||
|
ls | egrep '^[[:digit:]].*\.md|txt' | tail -n 1 | awk '
|
||||||
|
|
||||||
|
BEGIN {
|
||||||
|
# set field separator, blank by default
|
||||||
|
FS = "."
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
newnum = $1 + 1
|
||||||
|
nzeros = length($1) - length(int(newnum))
|
||||||
|
|
||||||
|
# could I do this with a simpler regex to select all leading zeros?
|
||||||
|
leadingzeros = ""
|
||||||
|
if (nzeros > 0)
|
||||||
|
for (i = 1; i <= nzeros; i++)
|
||||||
|
leadingzeros = sprintf("%s%s", leadingzeros, "0")
|
||||||
|
|
||||||
|
if (nzeros > 0)
|
||||||
|
newnum = sprintf("%s%s", leadingzeros, newnum)
|
||||||
|
|
||||||
|
# start by prefixing the number, now with leading zeros
|
||||||
|
finalstr = newnum
|
||||||
|
|
||||||
|
# allow an arg input to fill out descriptor string.
|
||||||
|
# single quote break to allow the shell to fill it out, double quotes so awk will treat it as a string
|
||||||
|
arg = "'$1'"
|
||||||
|
|
||||||
|
if (arg != "")
|
||||||
|
finalstr = sprintf("%s.%s", finalstr, arg)
|
||||||
|
|
||||||
|
# append last field by default
|
||||||
|
finalstr = sprintf("%s.%s", finalstr, $NF)
|
||||||
|
|
||||||
|
# previous loop to reassemble all fields. But I do not want the old middle string here
|
||||||
|
# Keeping it here for reference.
|
||||||
|
# for (i = 2; i <= NF; i++)
|
||||||
|
# finalstr = sprintf("%s.%s", finalstr, $i)
|
||||||
|
# }
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
END {
|
||||||
|
print finalstr
|
||||||
|
}'
|
||||||
|
`
|
||||||
0
bash/next/test/001.md
Executable file
0
bash/next/test/001.md
Executable file
0
bash/next/test/002.blah.md
Executable file
0
bash/next/test/002.blah.md
Executable file
0
bash/next/test/004.foo.md
Executable file
0
bash/next/test/004.foo.md
Executable file
0
bash/next/test/005.md
Executable file
0
bash/next/test/005.md
Executable file
0
bash/next/test/009.boo.md
Executable file
0
bash/next/test/009.boo.md
Executable file
0
bash/next/test/098.baa.md
Executable file
0
bash/next/test/098.baa.md
Executable file
0
bash/next/test/099.poo.md
Executable file
0
bash/next/test/099.poo.md
Executable file
43
bash/rename/rename.sh
Executable file
43
bash/rename/rename.sh
Executable file
|
|
@ -0,0 +1,43 @@
|
||||||
|
# rename : renames the string descriptor used in numbered series.
|
||||||
|
|
||||||
|
# Usage:
|
||||||
|
|
||||||
|
# > rename 100.md bar
|
||||||
|
# or
|
||||||
|
# > rename 100.foo.md bar
|
||||||
|
|
||||||
|
# is equivalent to:
|
||||||
|
# > mv 100.md 100.bar.md
|
||||||
|
# > mv 100.foo.md 100.bar.md
|
||||||
|
|
||||||
|
# split the args by a newline so that awk reads them as separate "records"
|
||||||
|
mvcmd=`echo "$1
|
||||||
|
$2" |
|
||||||
|
awk '
|
||||||
|
BEGIN {
|
||||||
|
# Builtin variable, "field seperator". The neatness of this is the main reason
|
||||||
|
# I use awk to parse the filename.
|
||||||
|
FS="."
|
||||||
|
oldname = ""
|
||||||
|
num = ""
|
||||||
|
ext = ""
|
||||||
|
newname = ""
|
||||||
|
}
|
||||||
|
|
||||||
|
NR == 1 {
|
||||||
|
oldname = $0
|
||||||
|
num = $1
|
||||||
|
# important that this is the last field, not numbered, to allow for a file
|
||||||
|
# without a string descriptor.
|
||||||
|
ext = $NF
|
||||||
|
}
|
||||||
|
|
||||||
|
NR == 2 {
|
||||||
|
newname = sprintf("%s.%s.%s", num, $0, ext)
|
||||||
|
}
|
||||||
|
|
||||||
|
END {
|
||||||
|
print oldname, newname
|
||||||
|
}
|
||||||
|
'`
|
||||||
|
mv $mvcmd
|
||||||
0
bash/rename/test/001.bar.txt
Executable file
0
bash/rename/test/001.bar.txt
Executable file
0
bash/rename/test/06.foo.md
Executable file
0
bash/rename/test/06.foo.md
Executable file
0
bash/rename/test/07.blah.txt
Executable file
0
bash/rename/test/07.blah.txt
Executable file
0
bash/rename/test/100.foo.md
Executable file
0
bash/rename/test/100.foo.md
Executable file
0
bash/rename/test/245.blah_foo.md
Executable file
0
bash/rename/test/245.blah_foo.md
Executable file
191
uldb.el
Normal file
191
uldb.el
Normal file
|
|
@ -0,0 +1,191 @@
|
||||||
|
;;; uldb.el --- An ultralight database for composition. -*- lexical-binding: t -*-
|
||||||
|
|
||||||
|
;; by bth
|
||||||
|
|
||||||
|
;; An ultralight database for writing and project composition, using only unique
|
||||||
|
;; filenames, POSIX filesystem conventions, and the builtin `project' package.
|
||||||
|
|
||||||
|
;; This is somewhat like org-roam, except without any database dependency. (And
|
||||||
|
;; it uses Markdown rather than org, which I don't care for.)
|
||||||
|
|
||||||
|
;; This depends on a few simple ideas:
|
||||||
|
|
||||||
|
;; 1. A numbered filename specification which serves as unique id.
|
||||||
|
|
||||||
|
;; 2. Placing that same id into the file header, so that concatenated files
|
||||||
|
;; have reference back to their source.
|
||||||
|
|
||||||
|
;; 3. Using a source "journal/" directory, where source files should first be
|
||||||
|
;; composed and where we can assume a file exists if not elsewhere.
|
||||||
|
|
||||||
|
;; 4. Using the built-in `project' package to organize compositions built from
|
||||||
|
;; these source files.
|
||||||
|
|
||||||
|
;; 5. (Optional) Use `embark' to visit files with a single keystroke.
|
||||||
|
|
||||||
|
;; features provided:
|
||||||
|
;; `uldb-journal-header' defines the standard header
|
||||||
|
|
||||||
|
;; `uldb-project-find-meta' via `project-switch-project': open a file like
|
||||||
|
;; *meta.md in a given project.
|
||||||
|
|
||||||
|
;; `uldb-file-at-point-advice' via `embark-dwim': open file in known projects
|
||||||
|
;; with fallback to journal/
|
||||||
|
|
||||||
|
;; `uldb-grep-tag': search files with same tag
|
||||||
|
|
||||||
|
(require 'package)
|
||||||
|
|
||||||
|
;; Primary path glob for the journal. This allows various mountpoints.
|
||||||
|
|
||||||
|
(setq uldb-journal-path-glob ".*/writing/journal")
|
||||||
|
|
||||||
|
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||||
|
;; journal header
|
||||||
|
|
||||||
|
(defun uldb-iso-8601 ()
|
||||||
|
"Insert a date stamp in ISO 8601 order, but with periods in place of dashes."
|
||||||
|
(format-time-string "%Y.%m.%d")
|
||||||
|
)
|
||||||
|
|
||||||
|
(defun uldb-journal-header ()
|
||||||
|
"Create a uldb-journal header composed of:
|
||||||
|
# buffer-name minus the .md file type
|
||||||
|
: date
|
||||||
|
"
|
||||||
|
(interactive)
|
||||||
|
(insert
|
||||||
|
(format "# %s\n: %s\n\n" (substring (buffer-name) 0 -3) (uldb-iso-8601))
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||||
|
;; journal/.project.el
|
||||||
|
|
||||||
|
;; normally .git detection works fine. But for my journal/ I don't git.
|
||||||
|
;; https://michael.stapelberg.ch/posts/2021-04-02-emacs-project-override/
|
||||||
|
(defun uldb-project-override (dir)
|
||||||
|
"Returns the parent directory containing a .project.el file,
|
||||||
|
if any, to override the standard project.el detection logic when
|
||||||
|
needed.
|
||||||
|
"
|
||||||
|
(let ((override (locate-dominating-file dir ".project.el")))
|
||||||
|
(if override
|
||||||
|
(list 'vc nil override)
|
||||||
|
nil)))
|
||||||
|
;; Cannot use :hook because 'project-find-functions does not end in -hook
|
||||||
|
(add-hook 'project-find-functions #'uldb-project-override)
|
||||||
|
|
||||||
|
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||||
|
;; find-file-at-point
|
||||||
|
|
||||||
|
;; the journal/ serves as content origin, so it must be treated specially.
|
||||||
|
(setq uldb-journal-path (car (seq-filter
|
||||||
|
(lambda (path)
|
||||||
|
;; this way I don't have to hardcode the full path:
|
||||||
|
(string-match uldb-journal-path-glob path))
|
||||||
|
;; stores all project roots in a list of strings:
|
||||||
|
(project-known-project-roots))))
|
||||||
|
|
||||||
|
;;;;;;;;;;;;;;;;;;;;;
|
||||||
|
;; find-file C-x C-f solution
|
||||||
|
;; combined with the hook into `file-name-at-point-functions', this means I can
|
||||||
|
;; run find-file at point, followed by M-n :
|
||||||
|
(defun uldb-journal-find-file ()
|
||||||
|
(let ((default-directory uldb-journal-path)
|
||||||
|
(thing (thing-at-point 'filename))
|
||||||
|
)
|
||||||
|
(expand-file-name thing))
|
||||||
|
)
|
||||||
|
(add-hook 'file-name-at-point-functions 'uldb-journal-find-file nil t)
|
||||||
|
|
||||||
|
;;;;;;;;;;;;;;;;;;
|
||||||
|
;; Embark solution (optional)
|
||||||
|
|
||||||
|
;; Load this with an advice:
|
||||||
|
;; (advice-add 'embark-target-file-at-point :around 'uldb-file-at-point-advice)
|
||||||
|
|
||||||
|
;; `embark-target-file-at-point' uses `ffap-file-at-point', which uses
|
||||||
|
;; `default-directory' to expand the filename.
|
||||||
|
|
||||||
|
;; NOTE: decided to use an advice rather than add my own function to
|
||||||
|
;; `embark-target-finders', since I'd have to remove the file finder and put my
|
||||||
|
;; function in the same place in the list anyway.
|
||||||
|
|
||||||
|
(defun uldb-file-at-point-advice (origfunc)
|
||||||
|
"Like find-file-at-point, but checks all known project paths.
|
||||||
|
|
||||||
|
In this order:
|
||||||
|
1. current project root
|
||||||
|
2. all other project roots
|
||||||
|
3. journal/ path
|
||||||
|
|
||||||
|
Since journal/ is the origin and other projects shadow it.
|
||||||
|
|
||||||
|
TODO: Use a special directory name for potentials/ or the like, in case it's not
|
||||||
|
in the root dir.
|
||||||
|
"
|
||||||
|
(or
|
||||||
|
;; current project
|
||||||
|
(funcall origfunc)
|
||||||
|
|
||||||
|
;; all other projects
|
||||||
|
(let ((result))
|
||||||
|
(cl-loop for project-path in
|
||||||
|
(seq-remove
|
||||||
|
(lambda (path)
|
||||||
|
(or (string-match uldb-journal-path path)
|
||||||
|
(when (project-current)
|
||||||
|
(string-match (caddr (project-current)) path))
|
||||||
|
))
|
||||||
|
(project-known-project-roots))
|
||||||
|
do (let ((default-directory project-path))
|
||||||
|
(setq result (funcall origfunc)))
|
||||||
|
if result
|
||||||
|
return result
|
||||||
|
))
|
||||||
|
|
||||||
|
;; journal path
|
||||||
|
(let ((default-directory uldb-journal-path))
|
||||||
|
(funcall origfunc))
|
||||||
|
))
|
||||||
|
|
||||||
|
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||||
|
;; C-x p p
|
||||||
|
|
||||||
|
(defun uldb-project-find-meta ()
|
||||||
|
(interactive)
|
||||||
|
;; this works because `project-switch-project' overrides the dir:
|
||||||
|
(find-file (expand-file-name "*meta.md" (caddr (project-current))) t)
|
||||||
|
)
|
||||||
|
|
||||||
|
;; overwrite
|
||||||
|
(setq project-switch-commands
|
||||||
|
'(
|
||||||
|
(uldb-project-find-meta "open meta" "m")
|
||||||
|
(project-dired "dired")
|
||||||
|
(project-find-file "find file")
|
||||||
|
(project-find-regexp "find regexp")
|
||||||
|
))
|
||||||
|
|
||||||
|
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||||
|
;; tags
|
||||||
|
|
||||||
|
;; TODO: do I want to search all projects?
|
||||||
|
(defun uldb-grep-tag ()
|
||||||
|
"Run project-find-regexp on the current identifer as a journal frontmatter tag.
|
||||||
|
|
||||||
|
NOTE: this searches in the current project root only.
|
||||||
|
"
|
||||||
|
(interactive)
|
||||||
|
(project-find-regexp (concat "\\+\\ " (thing-at-point 'word)))
|
||||||
|
)
|
||||||
|
|
||||||
|
;; NOTE: to export files with a given tag:
|
||||||
|
;; grep -l '\+ TAG' *md | xargs cp -t /tmp/
|
||||||
|
;; note the -l flag to grep to output files only, and the -t flag to cp to
|
||||||
|
;; specify a target dir (since it appends the list from xargs I think).
|
||||||
|
;; Or, in dired, run `find-grep-dired'.
|
||||||
|
|
||||||
|
|
||||||
|
(provide 'uldb)
|
||||||
Loading…
Reference in a new issue