Hacker News new | past | comments | ask | show | jobs | submit login
Sorting in Emacs (susam.net)
152 points by susam on Aug 12, 2023 | hide | past | favorite | 44 comments



Org mode is recommended if you have tabular data, in case there are any Emacs users that still haven't tried it. (Which might sound ridiculous - but who knows? I still haven't used magit! I've been using Emacs since 2006.)

You can sort the table using M-x org-table-sort-lines.

(Org mode tables, while simple plain text, are very readable. Anybody not using Emacs is going to find them tedious to edit though.)


If you use both git and Emacs but not magit, you're missing out. It's so good that it makes me keep Emacs open even when I'm using another editor or an IDE. These days pretty much everything has basic git integration, but few interfaces can match magit at doing non-trivial operations conveniently. With magit, it only takes a few keystrokes to selectively commit some changed lines, reword a past commit, do an interactive rebase, or use the reflog.


Go use Magit! Probably my favorite part of Emacs.


It’s literally the reason that keeps me in emacs, honestly.


I definitely tried and it definitely didn't work for me because something something ~/.Xdefaults or whatever.

But I hear good things.


It’s my favorite git client altogether.


yeah, I keep Emacs open just for Magit even when using other editors.


Magit revolutionized my git workflow. Rebase went from being a chore that I put off to easy peasy. My coworkers think I'm some kind of git wizard.


For me, being able to go straight from a selection in a code file to a log of all changes to that specific code, which I can then filter further, is what gets the strongest reactions from my coworkers.


WHAT!? You can use M-x magit-log-buffer-file with an active selection and see only the changes to the selected portion? This is so obvious in hindsight and so cool... Thanks a million!


TIL magit-log-buffer-file...


It's unfortunately hidden because it has no default keybinding iirc, but I love this feature. I think I discovered it by wondering if it exists, so I searched through the M-x candidates with orderless and typed in terms that I guessed could be part of the right name.


C-c M-g l gets you there. (C-c M-g leads to a submenu that also has blame.)

Until this thread I didn't know it could also do regions.


What?! How do you do this? I love magic but haven't discovered this.


Anyone with a recommendation for a magit tutorial? Thanks


The documentation is very good. The Getting Started[0] page has all you need for basic operations. I haven't watched this particular video[1], but Prot's other Emacs content is great.

[0]: https://magit.vc/manual/magit/Getting-Started.html

[1]: https://www.youtube.com/watch?v=2-0OwGTt0dI


I watched the video. It is quite informative. The best thing about emacs videos are they creator is that all the keycommands show on the screen by default. Arguably one of the slickest features in emacs.


org-mode tables are great. So is magit, I highly recommend it! I'm comfortable with command line git, use it quite a lot, but I also use magit a lot, and magit is especially great as a much better `git add -p`.


If anything, magit made me more comfortable with command line Git, by helping me discover things (--force-with-lease) and grok concepts (history editing) that I otherwise would not learn as quickly.


> org-mode tables are great

True, though they tend not to be very fast when they grow. (I have a table with almost 2000 rows and editing it lags a bit.)


I found that keeping tables narrow (not too many characters per line) helps. I try to build my tables so that most of the logic (I do spreadsheets with them) is oriented towards more rows instead of more columns.

However, I've not had 2000 lines tables yet. Perhaps a good trick is to divide them into multiple ones? Perhaps one for each category of things, if you have any different categories.


> magit is especially great as a much better `git add -p`.

In Git, except for when adding new files, I always use `git add -p` to stage changes. And it's definitely the number one thing I do with Magic in terms of frequency. I can confirm that if you're an `add -p` kinda person, you'll love Magit.


I often want to sort within a line:

    [“zoo”, “cow”]
Would become

    [“cow”, “zoo”]
Any tips on how to do that? Ideally using just built in functions…

I usually insert newlines between the elements, use a line-based sort, then recombine the lines. That works but is more tedious than I’d like. I’ve never taken the time to wrap that logic it in a function because it’s infrequent and it seems like it’s always slightly different.


I found this on the Emacs Wiki [1]. It seems to work:

    (defun sort-symbols (reverse beg end)
      "Sort symbols in region alphabetically, in REVERSE if negative.
    See `sort-words'."
      (interactive "*P\nr")
      (sort-regexp-fields reverse "\\(\\sw\\|\\s_\\)+" "\\&" beg end))
[1]: https://www.emacswiki.org/emacs/SortWords


Probably simplest is to not overthink and just write elisp, which is a fairly normal language.

    (defun my-sort-list ()
      (interactive)
      (when (not (looking-at (rx "[")))
        (search-backward "[" nil t))
      (when-let* ((line (thing-at-point 'sexp t))
                  (items (split-string (substring line 1 -1) (rx ",") t (rx blank)))
                  (sorted (string-join (sort items #'string-lessp) ", ")))
        (kill-sexp)
        (insert "[" sorted "]")))
I don't think I am using any non-builtin function here, though I think a few exceptions like s.el, f.el and dash.el can make things much easier.


"split-string" works well for this situation but for a case where there are commas inside some of the strings it would chop in the middle of those strings. So for the latter case and assuming the commas are consistently formatted, a safer approach might be starting in front of the first s-expression and then traversing to the tail of each s-expression with "forward-sexp" and check to see if a comma is there as expected and then delete the comma there (except for the last item with no comma) .


Yeah that's the classic comma in CSV problem. The solution is to indeed use a proper grammar/parser. The "forward-sexp" understands that as per major-mode rule as you say. Another more modern and declarative solution would be to take advantage of the full parse tree at your disposal thanks to tree-sitter (available in Emacs 29.1). Then you can simply do:

    (let ((list (treesit-thing-at-point "list" 'nested))
          (query "(list (string (string_content) @item))"))
      (cl-loop for (_ . item) in (treesit-query-capture list query)
               collect (treesit-node-text item t)))


Select the line, then type

    C-u M-| jq -c sort


I've been using Emacs for over 40 years but still find the shell my go-to sorting approach. Right tool for the job and all that.


I lean a fair bit in the opposite direction. If a sort is any more complex than -n or -k<number no flags>, I tend to vipe¹ my sort in my editor.

It feels great when you can use narrow-to-region² to perfect a complex address or write a custom function with all your editor's power at your fingertips. With the sad, but obvious, drawback that the changes aren't linked in your disjoint shell and editor history.

¹ https://manpages.debian.org/jessie/moreutils/vipe.1.en.html

² Nowadays, that is more likely https://github.com/chrisbra/NrrwRgn for me.



Keyboard macro. You convert the arrays into lines, you sort the result and then turn them back into arrays. If you do this often you could store the macro as an interactive command.


and for larger lists maybe a C-u shell-command-on-region to a script


Copy to clipboard, paste into your interactive Python window, and use as the argument to sorted. Copy and paste the interpreter's output back into your code.


You technically described how to make a word sorting macro execute arbitrary code.

Fascinating to think how that doesn't mean it's bad advice. That is, unless your threat model includes targeted attacks by three-letter-scale adversaries — and then you maybe just don't open untrusted files in Emacs or use advice from strangers on HN.


That's a good point. My assumption, not that I ever stated it, was that the list would be one you'd typed out yourself, or was one that was just there in code already, and you could verify by eye that it's just string literals.

Using Python's eval with empty globals and locals dicts (consult the docs) could make this safer, though I've only ever had to use that for defending against accidents rather than malice. And now this quick thing is becoming increasingly complicated, and maybe you'd be better off engineering it properly.


This is actually a rather common thing to do.. I have functions that run shell commands in my spacemacs config to do things like this. For example I've got one that runs `date` to insert today's date in a particular format.


>Copy to clipboard, paste into your interactive Python window

python-shell-send-statement, it's built into Emacs's python mode.


I was thinking you'd need it pasteable to pass it into sorted, but, yes, you could probably just evaluate it and then do sorted(_).


Why bother recombining the lines?


Mostly to pretty it back up into the original shape (so it matches what was already in git)


Take one hit on format - your change is also only a format change.


Sorting in Emacs, with my setup? I'm going to keep my fingers on the C-g keys...


In vim, :%!sort... does the trick.




Join us for AI Startup School this June 16-17 in San Francisco!

Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: