1 line
5.7 KiB
Plaintext
1 line
5.7 KiB
Plaintext
<!-- SC_OFF --><div class="md"><p>Hello all! I'm learning emacs lisp and getting used to the language. Yesterday I was trying to write a function to build and execute a shell command that I type frequently, to backup some of my files to google drive. I could make it work by hardcoding the commands, but as a learning exercise, I decided to try some fancy, overengineered stuff, to see if I can incorporate what I'm thinking in Elisp.</p> <p>Well, I couldn't. I still get confused with the function/var namespace separation, and the multiple ways I can declare things (<code>let</code>, <code>letf</code>, <code>flet</code>, <code>defalias</code>, ...). When to use lambda functions or just quoted expressions. If I should use partial application or just macros (like the threading ones). Etc.</p> <p>What I wanted to write is something like this:</p> <p>Given a list of file paths:</p> <ol> <li><p>"Duplicate" each</p></li> <li><p>Prepend the local root directory to one part</p></li> <li><p>Prepend the remote root directory to the other</p></li> <li><p>If the remote (second) path is a file, transform it to its directory name*</p></li> <li><p>Build the shell command for each file <code>rclone copy local_path remote_dir_path</code></p></li> <li><p>Concatenate all commands with <code>;</code></p></li> <li><p>Execute (print) them</p></li> </ol> <p>*because <a href="https://rclone.org/commands/rclone_copy/">rclone's copy</a> command requires a directory as destination.</p> <p>In Python, I could write something like this:</p> <p>```python from os import path</p> <p>files = ['org/', 'pictures/image1.png', 'pictures/image2.png', 'readme.md']</p> <p>build_prepend_function = lambda prefix: lambda str: prefix + str prepend_local_root = build_prepend_function('~/') prepend_remote_root = build_prepend_function('d:macbook/') extract_dir_path = lambda file: \ file if file.endswith(path.sep) else path.dirname(file)</p> <p>build_move_to_remote_shell_command = lambda file: \ 'rclone copy {} {}'.format(prepend_local_root(file), extract_dir_path(prepend_remote_root(file)))</p> <p>commands = (build_move_to_remote_shell_command(file) for file in files) script = ';'.join(commands)</p> <p>print(script) ```</p> <p>I can even translate it to C#:</p> <p>```csharp using System.IO;</p> <p>var files = new List<string> { "org/", "pictures/image1.png", "pictures/image2.png", "readme.md" };</p> <p>Func<string, Func<string, string>> buildPrependFunction = prefix => str => $"{prefix}{str}"; Func<string, string> prependLocalRoot = buildPrependFunction("~/"); Func<string, string> prependRemoteRoot = buildPrependFunction("d:macbook/"); Func<string, string> extractDirPath = file => file.EndsWith(Path.DirectorySeparatorChar) ? file : Path.GetDirectoryName(file); Func<string, string> buildMoveToRemoteShellCommand = file => string.Format( "rclone copy {0} {1}", prependLocalRoot(file), extractDirPath(prependRemoteRoot(file) ));</p> <p>var commands = files.Select(buildMoveToRemoteShellCommand); var script = string.Join(';', commands);</p> <p>Console.WriteLine(script); ```</p> <p>Both cases yielding this as result:</p> <pre><code>rclone copy ~/org/ d:macbook/org/;rclone copy ~/pictures/image1.png d:macbook/pictures;rclone copy ~/pictures/image2.png d:macbook/pictures;rclone copy ~/readme.md d:macbook </code></pre> <p>But I'm strugling to replicate that in Emacs Lisp:</p> <p><code>elisp (defun fun () (interactive) (let* ((selected-files '("org/" "pictures/image1.png" "pictures/image2.png" "readme.md")) (build-prepend-fn (lambda (prefix) (apply-partially #'concat prefix))) (prepend-local-root (funcall #'build-prepend-fn "~/")) (prepend-remote-root (funcall #'build-prepend-fn "d:macbook/")) (extract-dir-path #'file-name-directory) (build-move-to-remote-shell-command (lambda (file) (format "rclone copy %s %s" (funcall #'prepend-local-root file) (funcall #'extract-dir-path (funcall #'prepend-local-root file))))) (commands '(mapcar #'build-shell-command selected-files)) (script '(string-join (funcall (commands)) ";"))) (message (funcall (script))))) </code></p> <p>While I'm continuously checking the documentation and practicing, it would be nice if somebody more experienced than me could pinpoint what is wrong in this one-to-one translation.</p> <p>And of course. I'm open to suggestions of how you would write this, preferably in a more functional way. I believe writing everything inside a <code>let</code> [or any other binding-] form is not the most idiomatic way of writing elisp, given all the features lisp can offer. But I'm interested in the exact translation since it helps me alot in learning how elisp works.</p> <p>Oh, and I'm also aware that I can manipulate remote files with TRAMP, but I still didn't get to learn it. One thing at a time!</p> <p><strong>tl;dr: Learning elisp. Would like to translate above Python/C# code to equivalent e-lisp, for learning purposes. Open for suggestions of how things are done in elisp.</strong></p> <p><strong>edit: gists available <a href="https://gist.github.com/mabo3n/9b86df34bcb68501eda4d16e576a61f1">here</a></strong></p> </div><!-- SC_ON -->   submitted by   <a href="https://www.reddit.com/user/kromobrn"> /u/kromobrn </a> <br/> <span><a href="https://www.reddit.com/r/emacs/comments/r0i8d6/help_me_translate_this_pythonc_code_to_emacs_lisp/">[link]</a></span>   <span><a href="https://www.reddit.com/r/emacs/comments/r0i8d6/help_me_translate_this_pythonc_code_to_emacs_lisp/">[comments]</a></span> |