reddit / emacs

Help with Elisp and TRAMP

remillard · 2022-12-21 15:18
Good morning, I have a situation where I'd like to automate something with TRAMP but my Elisp-fu is pretty weak. I can kinda read it and usually figure out what's going on, but that's a bit different from getting the thing to work. We have embedded development units with a little miniature network inside them for communications. I need to do dired (and ultimately file editing, but dired is a fine jumping off point) on files on the second hop. The second IP address is always the same, however the first can vary within our local network, and depending on which box we're shelling into. So for example a working argument to dired looks like: /plink:root@10.20.20.5|ssh:root@192.168.1.1:/ And this will give me the directory at the root filesystem on the second hop. The 192.168.1.1 address is always the same (it's inside the box) but the 10.20.20.5 might vary at the 5 depending on which box, and which IP address DHCP picked up that day when it powered on. Ideally it would just interactively ask me for the first address and then execute dired on the full string as I'm fine with using that as a starting point for editing the scripts and whatnot that end up on the machine. Anyone Elisp fluent who might point me in the right direction? Thanks in advance. I've read a lot on the Elisp programming manuals and such, but getting from the language to doing something functionally useful more than basic addition or something has eluded me thus far.
phr46 · 2022-12-21 15:54
(defun dired-miniature-network () (interactive) (let ((first-address (read-string "First address: "))) (dired (concat "/plink:root@" first-address "|ssh:root@192.168.1.1:/")))) This will prompt in the minibuffer for the address, concatenate it inside the working argument you provided, and call dired with it. I hope it works :D EDIT: code formatting, reddit hates me.
remillard · 2022-12-21 15:58
Hey I'll give it a shot, thanks! Honestly this LOOKS simpler than I thought it would (of course like I said in the post, reading is far different from writing.)
remillard · 2022-12-21 16:02
Absolutely worked first time, thank you!
doolio_ · 2022-12-21 19:09
Question: why is it necessary to have the double parentheses around `first-address`?
terminal_cope · 2022-12-21 19:19
That's just how `let` works - see `C-h f let`: let is a special form in ‘C source code’. (let VARLIST BODY...) Bind variables according to VARLIST then eval BODY. The value of the last form in BODY is returned. Each element of VARLIST is a symbol (which is bound to nil) or a list (SYMBOL VALUEFORM) (which binds SYMBOL to the value of VALUEFORM). All the VALUEFORMs are evalled before any symbols are bound.
terminal_cope · 2022-12-21 19:23
Slight tweak, you can specify the prompt for a string via `interactive`, so: (defun dired-miniature-network (hostname) (interactive "MFirst address: ") (dired (concat "/plink:root@" hostname "|ssh:root@192.168.1.1:/"))) Edit: I should explain - see `C-h f interactive` for the full explanation, but it declares how the argument (`hostname`) will be obtained. The "MFirst..." string indicates with "M" it's going to prompt for a string (full list in the help), and following that is the prompt text. The string entered becomes the argument to the function.
phr46 · 2022-12-21 19:34
The extra parentheses is required by how "let" works. let is a macro that allows you to do assignments, and the extra parentheses allows you to assign different variables with a single let. For example, if there was a second-address it might look like: (let ((first-address (read-string "First address: ")) (second-address (read-string "Another one: "))) (do-stuff-with first-address second-address)) There, now it should make more sense. One parentheses is for the list containing all the assignments, and then there's another parentheses around each pair of (variable-name value)
doolio_ · 2022-12-21 20:27
Yes, thank you. This makes it much clearer.
[deleted] · 2022-12-22 15:52
[deleted]