DWIM shell command
Excellent package to wrap repetitive shell commands into interactive commands.
Commands
csv to datasette
I keep having to interact with csv files and using datasette to explore the data would really be helpful sometimes.
(defun kes-dwim-shell-command-csv-to-sqlite ()
"Create a database file for the given csv file"
(interactive)
(dwim-shell-command-on-marked-files
"Create sqlite db for csv"
"sqlite-utils insert '<<fne>>.sqlite' dwim_import '<<f>>' --csv"
:utils "sqlite-utils"))
(defun kes-dwim-shell-command-open-datasette ()
"Open datasette for a sqlite db file"
(interactive)
(dwim-shell-command-on-marked-files
"Open datasette on sqlite db"
"datasette '<<f>>' -o"
:utils "datasette")
)
I can reduce this down to just one command like this
(defun kes-dwim-csv-to-datasette ()
"Convert csv into sqlite db and run datasette"
(interactive)
(dwim-shell-command-on-marked-files
"CSV to SQLITE to Datasette"
"sqlite-utils insert '<<fne>>.sqlite' dwim_import '<<f>>' --csv && datasette '<<fne>>.sqlite' -o"
:utils "sqlite-utils"
:focus-now t))
Here, :focus-now t
just means that the dwim-shell-command
buffer is brought into focus
so that we can see the output immediately.
csv to json
(defun kes-dwim-shell-command-csv-to-json ()
"Read large csv file and convert it to a json file"
(interactive)
(dwim-shell-command-on-marked-files
"Convert csv to json file"
"
import csv
import json
import sys
csv.field_size_limit(sys.maxsize) # sometimes the csv is too large
rows = csv.DictReader(open('<<f>>'))
newrows = []
for row in rows:
newrow = {}
for key, value in row.items():
try:
newvalue = json.loads(value) # sometimes the values might be json strings
# if not isinstance(newvalue, (dict, list)):
# don't care about scalar values that might be valid json
# newvalue = value
except Exception:
newvalue = value
newrow[key] = newvalue
newrows.append(newrow)
as_json = json.dumps(newrows, indent=2)
filename = '<<fne>>.json'
with open(filename, 'w') as f:
f.write(as_json)"
:shell-util "python3"
:shell-args "-c"
:silent-success t))
Using transient
I got inspired by Charles Choi's post about using transient with isearch so following is what I did.
kes-dired-transient
(require 'transient)
(transient-define-prefix kes-dired-transient ()
"dired menu"
[["CSV files"
("cj"
"Convert csv to json"
kes-dwim-shell-command-csv-to-json
:transient nil)
("cs"
"CSV to sqlite"
kes-dwim-shell-command-csv-to-sqlite
:transient nil)
("cd"
"CSV to Datasette"
kes-dwim-shell-command-csv-to-datasette
:transient nil)
]
["JSON files"
("jd"
"JSON to Datasette"
kes-dwim-shell-command-json-to-datasette
:transient nil)]
["Misc"
("fc"
"Fold certificate"
kes-dwim-shell-command-fold-cert
:transient nil)
("od"
"Open datasette"
kes-dwim-shell-command-open-datasette
:transient nil)
]])
(define-key dired-mode-map (kbd "C-c d") 'kes-dired-transient)
I'm sure I'll be adding more commands to this.