index rss mastodon twitter github linkedin email
Álvaro Ramírez
sponsor

Álvaro Ramírez

10 July 2022 Emacs: DWIM shell command (multi-language)

UPDATE: dwim-shell-command is now available on melpa.

csv.gif

I keep on goofying around with dwim-shell-command and it's sibling dwim-shell-command-on-marked-files from dwim-shell-command.el.

In addition to defaulting to zsh, dwim-shell-command-on-marked-files now support other shells and languages. This comes in handy if you have snippets in different languages and would like to easily invoke them from Emacs. Multi-language support enables "using the best tool for the job" kinda thing. Or maybe you just happen to know how to solve a particular problem in a specific language.

Let's assume you have an existing Python snippet to convert files from csv to json. With dwim-shell-command-on-marked-files, you can invoke the Python snippet to operate on either dired or buffer files.

(defun dwim-shell-command-csv-to-json-via-python ()
  "Convert csv file to json (via Python)."
  (interactive)
  (dwim-shell-command-on-marked-files
   "Convert csv file to json (via Python)."
   "
import csv
import json
text = json.dumps({ \"values\": list(csv.reader(open('<<f>>')))})
fpath = '<<fne>>.json'
with open(fpath , 'w') as f:
  f.write(text)"
   :shell-util "python"
   :shell-args "-c"))

Or, maybe you prefer Swift and already had a snippet for the same thing?

(defun dwim-shell-command-csv-to-json-via-swift ()
  "Convert csv file to json (via Swift)."
  (interactive)
  (dwim-shell-command-on-marked-files
   "Convert csv file to json (via Swift)."
   "
    import Foundation
    import TabularData
    let filePath = \"<<f>>\"
    print(\"reading \\(filePath)\")
    let content = try String(contentsOfFile: filePath).trimmingCharacters(in: .whitespacesAndNewlines)
    let parsedCSV = content.components(separatedBy: CSVWritingOptions().newline).map{
      $0.components(separatedBy: \",\")
    }
    let jsonEncoder = JSONEncoder()
    let jsonData = try jsonEncoder.encode([\"value\": parsedCSV])
    let json = String(data: jsonData, encoding: String.Encoding.utf8)
    let outURL = URL(fileURLWithPath:\"<<fne>>.json\")
    try json!.write(to: outURL, atomically: true, encoding: String.Encoding.utf8)
    print(\"wrote \\(outURL)\")"
   :shell-pipe "swift -"))

You can surely solve the same problem in elisp, but hey it's nice to have options and flexibility.