• 0 Posts
  • 17 Comments
Joined 1 year ago
cake
Cake day: October 17th, 2023

help-circle

  • Lots of critiques headed your way, so I’ll just say: well done. I hope your Vim friends use it and you therefore get to keep on Emacsing the way you want to, which is, of course, the Emacs way.

    I wonder if that’s what Emacs is about, for me—getting to finally do things my own way all the time with no compromises, and getting to periodically re-evaluate what “my own way” should be. In other words, no compromises but… my own… personal… time…

    Hmm.

    Shit.


  • What makes learning Emacs and Elisp so hard? I think you’ve begged the question in the classic sense—your question contains the answer! The issue I think is that to really understand Emacs you have to understand Elisp and the Emacs environment.

    If you focus only on one, it’s hard to work with Emacs. Knowing Elisp without understanding how to work with hooks, and modes, and when (and whether) to work with the Custom system, and when configuration code should load before vs. after a package loads… well, you’re not going to be able to do a whole lot with that Elisp! And Emacs knowledge without Elisp means you’re going to know what you want to do and maybe even how to do it but you’re going to have some fundamental misunderstandings of the code itself, leading to errors and bugs and a lot of frustration.

    Thinking about this, I think the reason the documentation can be so challenging to figure out is that, as someone said further up there, this is all run by volunteer efforts, and, as such, they have to prioritize where their limited resources go. So the approach it seems to me that they’ve taken is to document as much of the Emacs environment as they can, but focus not on all of Elisp, but how it’s different from other Lisps, and assume you can teach yourself Lisp.

    I’m not really sure it’s true that this was the purposeful prioritization from the documentation writers—there’s a pretty extensive Elisp manual, and a nice Elisp tutorial in the manual (typically C-h i)—but it’s not the level of resources nor the beginner-friendly approach that you see with learning a (somewhat) more practical Lisp, like Scheme or Racket or Common Lisp or Clojure. I don’t mean to put words in the mouth of the tireless and selfless documentation writers, nor at all demean them! But either way, it’s the same result from a learner’s perspective.

    So given the situation (as I see it), how do you learn Emacs? I highly recommend learning another Lisp, since there are more resources and tutorials on those than Elisp. Racket and Scheme.are IMO the easiest to get started with, and fun besides.

    One final thought on learning Emacs: I think I stunted my growth for a while by using a framework on top of Emacs—I learned neither proper Elisp nor how Emacs worked. I learned a little about how my framework worked, and little about Emacs itself. I used Doom Emacs, but most frameworks have this issue. I’ve heard there are some frameworks that are better geared towards teaching you Emacs, so maybe this doesn’t apply at all. But I think Doom Emacs is more geared to transitioning folks from Vim (which helped me, for sure!), and the framework they’ve built on top of it, while powerful, isn’t, in my “n of 1” experience, good for learning.

    Anyway, hope these thoughts help, and besides agreeing with folks that one of the best things you can do to learn and help others learn is to contribute to the documentation, this and the org-mode reddit are good places to ask clarifications—especially if it’s clear it’s a clarification and you’ve attempted your research first! (We’re friendly, but we’re friendlier if you demonstrate you’re putting in the effort too.)

    Cheers!





  • The two things that I would miss the most if I didn’t have them would be Evil Mode (even if my vanilla Emacs keybindings skills are getting a lot better) and the interlocking completion/filtering/sorting/querying/gosh-what-don’t-they-do systems of Vertico/Corfu/Orderless/Embark/Marginalia/Cape/Consult.

    When I mess up my config and have to use vanilla Emacs to find the silly thing I did, those are what slow me down.

    But once you have those (skipping Evil if you’re not a Vim user), for IDE-ness you probably want to explore the main major mode packages for those langauges, plus an LSP system (I like Eglot) to give you project-aware completion.

    Oh! And if you’re a big terminal user, Vterm will give you something powerful, something flexible, and the kind of terminal experience you’re used to. You can always explore Eshell later!

    Okay, and if you’re working with Git, which who isn’t, Magit is a must.

    Okay, I’ll stop before I’m simply listing all the packages I use!


  • Ugh, I hate to defend someone with “it was just a joke”, but I do think he was lightly mocking the OP’s approach.

    The link is also worth sharing with new folks—they WILL get better information if they learn to look for stuff on their own, and if new folks do a lot of research BEFORE they ask in a forum, they’ll understand their question better as well.

    All that said, while I don’t think he was being a total dickhead, yeah, it would be nicer if people shared that folks should do their own research in a kinder way.

    Either way, though, thanks for calling him out and making me think about how we approach newcomers!


  • It can be overwhelming getting started with Emacs, but if configuring your editor feels like a waste of time to you, then this probably isn’t the right time for Emacs in your life.

    But! If you see something you really like in Emacs, and you want to try to get a quick start and get to work, search the web for some articles on how to set it up as an IDE for ONE of those languages. Copy the code, make sure you’re putting it in the right place, and give it a shot! You may find yourself really liking the editor.

    I also recommend Doom Emacs, whether you’re coming from Vim or not, because it makes it easy to get yourself 90% of the way to what you want, configuration-wise, with RELATIVE ease.

    Good luck!


  • Slight improvement on your advising function, OP: this version starts the shell history you scroll through at index 1, so that after you go up one from your most recent-command, you don’t see the most recent command again.

    (defun crj--auto-fill-shell-commands (args)
      (list (car args) (car shell-command-history) '(shell-command-history . 1) (cdddr args)))
    
    (advice-add 'read-shell-command :filter-args #'crj--auto-fill-shell-commands)
    

    Is there a cleaner way to handle the args than this unpleasing cdddr? Something I can do with &rest?


  • I tweaked the answer somewhat, as it bothered me that we were getting the most recent command inserted and having it show up again when you decide to go back to an earlier command. In other words, with the OP’s advice, we get the most recent command in the minibuffer history twice, once auto-filled and once in the regular history.

    I’m sure there are cleaner ways to do it than using a custom global variable no other functions know about, which could I think lead to some weird side effects at some point… but for now, I like the behavior:

    (defvar crj-most-recent-shell-command (car shell-command-history))
    
    (defun crj--pop-shell-command-history (fn &rest _args)
      (setq crj-most-recent-shell-command (car shell-command-history))
      (let ((shell-command-history (cdr shell-command-history)))
        (apply fn _args)))
    
    (defun crj--auto-fill-shell-commands (args)
      (list (car args) crj-most-recent-shell-command))
    
    (advice-add 'read-shell-command :around #'crj--pop-shell-command-history)
    (advice-add 'read-shell-command :filter-args #'crj--auto-fill-shell-commands)
    

    Let me know if anyone has improvements/objections!



  • I like your thinking!

    Here’s a solution for automatically running the last command:

      (defun repeat-most-recent-shell-command-asynchronously ()
        (interactive)
        (async-shell-command (car shell-command-history)))
    

    It has two drawbacks:

    • shell-command-history doesn’t differentiate between asynchronous and synchronous shell commands, so you may accidentally repeat an async command synchronously (if you differentiate at all)—there are ways to look through the history for the one you want, however
    • you’re repeating automatically, not auto filling and giving yourself the chance to decide you want to run a different command instead

    Honestly probably not worth solving that second issue, as you could bind a function like the one above and then just use that binding instead of the usual when you want to repeat. (Actually, now that I’ve thought this through, I think that’s exactly what I’m gonna do.)

    If you want the auto fill behavior and not the repeat behavior, you could advise the shell-command functions to grab (car shell-command-history) and insert it into the minibuffer.

    Thanks for the thought-provoking question! I think I’m gonna go add this function now. : )



  • Check the documentation of async-shell-command (M-x describe-function async-shell-command RET), and you’ll see that it takes one necessary argument, the command to run.

    If you run it interactively (through its keybinding or M-x), it prompts you for that argument. Type in the command for Emacs, and Emacs will pass that as the argument to async-shell-command.

    But if you want to, you can call it from Lisp and pass in the argument yourself! Try executing it in the scratch buffer or by running eval-expression (I believe M-: by default).

    (async-shell-command "git status")
    

    That will run git status and give you the result

    Now if you want to run that bit of code more often, wrap it in a function and assign it a keybinding!

    (defun crj-check-git-status ()
      (interactive)
      (async-shell-command "git status"))
    
    (general-define-key (kbd "C-M-&") #'crj-check-git-status)
    

    Would anyone else handle this differently? I’m still learning myself!


  • if you don’t want to jump right into configuring things from scratch, I would recommend you start with Doom Emacs.

    I started with Doom Emacs (which I’ve heard is great even if you’re not an Evil user), but eventually found the abstractions frustrating and wanted to make Emacs truly my own, at which point I started over with a clean slate and now understand the configuration of my system a lot better.

    I wish I’d started configuring it from scratch on my own sooner, for sure, but I don’t know that you need to do so from the outset. If you just want to get work done while slowly getting used to the Emacs workflows, a configuration system like Doom’s can make that easier. It can also welcome you into Emacs without scaring you away.

    That said, the abstractions hide a lot of details of how Emacs works, so if you’re sure you’re in it for the long term and can take the time now—which is maybe what you mean by “studying Emacs”… it is a thing to study!—then by all means, start from scratch.

    Either way, I’ll echo u/nv-elisp above—when you’re trying to configure something, look at the documentation and articles online before you ask questions! You’ll learn how to learn, which will help you immensely with all future problems.

    I’d also recommend a couple of packages to make things easier:

    • The Helpful package makes the vital and helpful describe commands even more… helpful.
    • The Vertico/Marginalia/Corfu/Embark/Orderless/Counsel set of packages greatly improve your ability to navigate around Emacs.

    Good luck, and happy hacking!


  • Reviewed the code, great job on your first package—wouldn’t know it was your first if you hadn’t said so! I think you should definitely get it on MELPA.

    If you wanted a next step for it, you could consider giving users not just the option of set times, but:

    • tying it into the OS dark/light schedule
    • or tying into Emacs’ solar functions to get their local sunrise/sunset times
    • or making an API call to get local sunrise/sunset times.

    You could also give them an option to provide an offset to those times… maybe they want light theme 30 minutes after the sun rises and dark theme 45 minutes before the sun sets, for example.

    I did some thinking on this because I wanted to write a similar package at some point, before realizing I actually didn’t want to switch themes at all. : )

    No matter where you go with this, congrats on your first package. Well done!