gitweb.el -- Quickly visit a repo's forge from Emacs

Posted on 2019-10-21 10:41 +0100 in Emacs • Tagged with Emacs, git • 2 min read

gh.fish, which I wrote about yesterday, actually sprang from something I initially wrote for Emacs. I'm often spending my time switching between Emacs and the command line (which is fast and easy -- I normally work on macOS and have Emacs and iTerm2 running full screen, and I can switch between them without ever taking my hands off the keyboard), so it makes sense to have some handy commands repeated in both places.

So, originally, I'd written gitweb.el to open the current repo's "forge" in the web browser.

As with the fish version, how it works is quite simple. I use shell-command-to-string to call git and find the origin URL for the current repo, and then manipulate it a bit to turn it into a normal browser-friendly URL. Finally, if I get something workable, I use browser-url to have the resulting page open in the browsing environment of choice.

I have the command bound to a key combination that's similar to the ones I use with magit and forge, so in terms of muscle-memory it's easy for me to remember what to press when I quickly want to skip over from a magit view to the repo forge itself.

Similar to what I wrote a couple of days back, I think this again illustrates how handy Emacs is as a work environment. While it's absolutely true that there are other development environments out there that offer similar extensibility, Emacs is the one I'm comfortable with, and it has a long history of offering this.


pypath.el -- A little Emacs hack to help with Django

Posted on 2019-10-19 10:35 +0100 in Emacs • Tagged with Emacs, Python, Django, Lisp • 2 min read

One of the things I really like about coding with Emacs is how I can easily identify a repeated task and turn it into a command in my environment, saving me a load of work down the line.

pypath.el is one such example.

In my day job I write a lot of Django code. As part of that, I write a good number of unit tests too. Sometimes I'll write the tests as I'm writing the code they test, other times I'm writing them afterwards; it all really depends on where my head's at and how the code is flowing.

When I'm writing those tests, I often want to test them as I go. Given that starting up a test session can take a while, and given that running all the tests in the system can take a while, it's really handy if I can run that single test I'm working on.

This is easy enough with Django. In my work environment it's normally something like:

$ pipenv run ./manage.py test -v 2 app.test.some.sub.module.TestClass.test_method

Only... typing out the:

app.test.some.sub.module.TestClass.test_method

part is a bit of a pain. Sure, once you've typed it the once you can use your shell of choice (mine being fish and on occasion eshell) to recall it from history, but typing it out the first time is the annoying part.

So this was the point where I took 1/2 hour or so to code up pypath.el to solve the problem for me. It gives me two commands:

  • pypath: which simply places the dotted path of the current "defun", within the context of being part of a Django system, into the clipboard buffer.
  • pypath-django-test: which works similar to the above but places the whole Django testing command into the clipboard.

With the above, I can work on a test, hit the latter command above, flip to my command line, paste and I'm running the test.

Of course, I'm sure there's plenty of other handy ways to do this. Doubtless there's work environments where the test can be run right there, in the edit buffer, without flipping away, and which takes into account the fact that there's a pipenv-managed virtual environment involved, etc. If there is, that's great, but I don't think it'd work with how I work.

And that's one of the things I really love about Emacs, and why it's still my work environment after almost 25 years of on and off use: with very little work on my part I can create a couple of commands that work exactly how I need them to. While it's great to create generally-useful code for Emacs that lots of people benefit from, sometimes the real value is that you can code up your own particular quirk and just get on with stuff.

To conclude: this post isn't to show off pypath.el; really this post is to sing the praises of Emacs and why it still works so well for me after all these years.


More revamping of my Emacs config

Posted on 2017-07-13 15:25 +0100 in Emacs • Tagged with Emacs, Lisp, coding, Emacs Lisp • 2 min read

I've been pretty quiet on here since I last wrote about how I'd done a further revamp of my Emacs config, so I thought that subject would be a good reason to write another blog post.

It'll be a mostly short one, and one to muse over something that's been bugging me for a while now: my decision to lean heavily on customize to set all sorts of settings.

Initially, when I nuked my original config over a year ago, it seemed to make a lot of sense. Let all the tweaks and set values "hide" in a file of their own and try and keep the hand-edited config files as small and as clean as possible. Recently though I've got to thinking that this obscures too much, hides too much detail, and removes the ability to actually document what I'm doing and why. It also does make it tricky to adapt some settings to different platforms or even environments on a single platform.

Another problem I've run into is this: when I made the second round of changes and decided to lean heavily on use-package, I soon ran into the minor issue of some packages not making sense, or even being needed, on some platforms (stuff that's useful on my macOS machines isn't always useful on my Windows machines, that sort of thing). While use-package can handle this easily thanks to the :if keyword, I'm still left with the fact that package-selected-packages still gets populated.

Having package-selected-packages contain a list of installed packages likely makes sense if you're using just the Emacs package system and you're not doing the installing with use-package and :ensure. But with use-package and :ensure I feel like I've got far more control over things and can adapt what gets installed when depending on which Emacs I'm running where.

But, because I'm syncing my ~/.emacs.d/.custom.el to all my machines too, any use-package that has a :if to not bother using a package has little effect because the package still ends up being listed/loaded/seen as part of the installation.

Ideally, I think, I'd like to be able to have package-selected-packages held in its own file, or I'd only ever use ~/.emacs.d/.custom.el for local stuff (and so stop syncing it).

Starting today I'm going about a process of moving as much as I can out of ~/.emacs.d/.custom.el and into hand-edited files. In some respects I guess I am going back to how I used to manage Emacs configuration, but this time it's not a massive monolithic file-of-Lisp, it's neatly broken down into sensible sections and it's also biased towards a "grab and config this package" approach.

Meanwhile, I've not seen any good discussions online about customize vs "hand-edit", which strikes me as a little odd as it feels like the perfect "religious issue" for people to have endless disagreements over. I guess, over the next couple or so weeks, I'll find out if switching back was a good idea.


Another revamp of my emacs config

Posted on 2017-04-01 10:02 +0100 in Emacs • Tagged with Emacs, Lisp, Emacs Lisp, coding • 4 min read

Just under a year ago I decided to totally rewrite my GNU emacs config. As I wrote at the time, it'd been following me around all sorts of machines since the early 1990s, starting life on an OS/2 Warp machine and travelling via MS-DOS, GNU/Linux, Windows and, these days, macOS.

The changes I made last year have served me really well, but there were two related issues with it that bothered me a little: the fact that I was maintaining a local library of elisp code in the repository and, worse still, I was storing the packages I'd installed from elpa and melpa in the repository as well.

While this did mean it was pretty easy for me to start up a new installation of emacs on a machine -- all I had to do was clone the repo and run up emacs -- I wasn't happy with the duplication involved. I didn't like holding code in my .emacs.d repo that was already held in package archives.

The solution I saw was in two parts:

  1. Get some of my code, that might be useful to others, into melpa.
  2. Somehow sort my own package archive for my personal code.

Over the past week or so I've worked on this approach. It initially started with me tackling item 1 above: I tidied up and submitted obfusurl.el, protocols.el, services.el, thinks.el and uptimes.el. This was a really helpful process in that it allowed me to brush up on my elisp and emacs knowledge. It's a good 15+ years since I last wrote any significant elisp code and things have moved on a little in that time.

Having done that I'd managed to move a handful of my own packages out of my local library of code, and so out of my .emacs.d repo, but it left me with the problem of what to do with the rest of it.

That's when I discovered package-x and:

,----[ C-h f package-upload-buffer RET ]
| package-upload-buffer is an interactive compiled Lisp function in
| package-x.el.
|
| (package-upload-buffer)
|
| Upload the current buffer as a single-file Emacs Lisp package.
| If package-archive-upload-base does not specify a valid upload
| destination, prompt for one.
`----

(plus package-upload-file too, of course). This meant I could, in effect, start my own personal package archive and look at tackling issue 2 above.

This did give me one small problem though: how and where would I host the archive? I did consider hosting it on a DigitalOcean droplet, but that felt a little like overkill for something so simple. And then I realised: GitHub Pages! All I needed to do was keep the package archive in its own repo (which I would have done anyway) and then make the whole repo the source for a GitHub Pages site. A quick test later and... it worked!

So, by this point, I'd farmed some of my code off to melpa, and now had the rest of it in "delpa" (which I'd called my personal archive). I could now use the emacs package management system to install third party packages and also my own.

But I was still left with one issue: I was still holding the installed packages inside my .emacs.d repo by way of ensuring that all machines were in sync in terms of what was installed. Now I needed to work out how to solve that.

Around this time, as luck would have it, @tarsius had suggested I look at a package called use-package by @jwiegley. This was the bit I was missing.

With use-package I would be able to declare which packages I needed, how they'd be installed and, most important of all, it could be set to handle the fact that the package wasn't even installed. If a package is requested and there is no local install use-package is smart enough to get the emacs package system to install it.

So, given that, all I need to do was create a startup file that would declare the packages I use and I'd have a setup that should, once I'd cloned .emacs.d, self-install.

Except... yeah, one more issue. use-package isn't part of GNU emacs yet so I'd need a method of getting it to auto-install so it could then handle everything else. As it was that was as easy as adding this to the start of my init.el.

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; Make sure the package system is up and running early on.
(require 'package)
(add-to-list 'package-archives '("melpa" . "http://melpa.org/packages/"))
(add-to-list 'package-archives '("delpa" . "http://blog.davep.org/delpa/"))
(package-initialize)

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; Bootstrap `use-package'
(unless (package-installed-p 'use-package)
  (package-refresh-contents)
  (package-install 'use-package))

With that in place I was able to nuke all my config on a machine, clone a fresh copy of .emacs.d (having now ceased tracking and storing the installed packages in that repo), run up emacs, wait a few moments and then find that everything was installed and ready to use.

Perfect!

My .emacs.d is now a lot smaller than it was before and, I think, even easier to maintain. Right now I think I'm very close to the ideal emacs config that I wanted to create when I did the complete rewrite a year ago.


Starting fresh with GNU emacs

Posted on 2016-05-26 12:28 +0100 in Emacs • Tagged with Emacs • 4 min read

As I've mentioned elsewhere on this blog, over the past few years, my use of GNU emacs has lapsed somewhat. There was a time when it was my only editor (except for the odd dips into vim to do some quick editing) and, back when I used to use GNU Linux as a desktop machine a lot, I'd have an emacs session up and running pretty much non-stop (it was one of the reasons I wrote uptimes.el).

In more recent times I've been working more on Windows and often inside Visual Studio. Even for my own "for fun" programming, I've mostly being doing things that didn't involve emacs much. In fact, most of my recent "for fun" coding has been done using Sublime Text because it was powerful, cross-platform and also had great support for the language I code in a lot when it comes to personal amusement projects.

During that time I've wanted to get back into emacs. Quite a bit seems to have changed since I was last a very avid user and this also meant wanting and needing to catch up.

The first thing I needed to do was finally get around to killing off my old ~/.emacs file. This has followed me around since I first got into emacs on OS/2 back in the mid 1990s. The file started out with a few setq expressions to tweak some settings and just kept growing and growing. It'd got to a point where there was old stuff in there that I had no use for and sometimes even no idea what it was for. Heck, to give some idea of how old the file was: there were items in there that handled running emacs on MS-DOS!

So, a couple of weeks back, I dumped it. Dumped the whole lot. The plan then was to recreate it with as little hands-on coding as possible. I decided that, as much as I could, I'd tweak using customize and only hand-code (in ~/.emacs.d/init.el this time around) things when there was no obvious other way to do it.

So far this is working out really well. Gone has the ugly and monolithic .emacs, replaced with something far more modular, much more tidy and far easier to maintain. Whereas my old config was almost 1,000 lines long, the new init.el is currently just 50 lines:

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; Make use of the Common Lisp compatibility module.
(require 'cl)

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; Local config/lib directory support.

(defun davep:user-path (path)
  "Given `file', return a path for it in the local config."
  (concat user-emacs-directory path))

(defvar davep:local (davep:user-path "davep/")
  "My local config and code directory.")

(defvar davep:startup (davep:user-path "davep/startup")
  "My local startup code.")

(defvar davep:lib (davep:user-path "davep/lib")
  "My local library code.")

(defvar davep:lib-3rd-party (davep:user-path "davep/lib-3rd-party")
  "My local third party code.")

(push davep:local         load-path)
(push davep:startup       load-path)
(push davep:lib           load-path)
(push davep:lib-3rd-party load-path)

(defun have-own-package-p (package)
  "Does a package of my own exist in this environment?"
  (locate-library package nil (list davep:lib)))

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; Ensure custom values go in their own file.
(setq custom-file (davep:user-path "custom.el"))
(load custom-file)

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; Load various startup things.
(load "env-tests")
(require 'davep-keys)
(require 'davep-languages)
(require 'davep-style)
(require 'uptimes)
(require 'csrclr)

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; Local autoloading.
(require 'autoloading)
(load-davep-autoloads)

All the other stuff, things to tweak language modes so they indent "just so", my own special keyboard bindings, that sort of thing, they're all farmed off into their own files:

davep@Bellerophon:~/.emacs.d/davep/startup$ v
total 40
-rw-r--r--  1 davep  staff  4211 24 May 14:38 davep-keys.el
-rw-r--r--  1 davep  staff  4078 16 May 13:51 davep-languages.el
-rw-r--r--  1 davep  staff   537 25 May 14:13 davep-style.el
-rw-r--r--  1 davep  staff  1339 16 May 09:39 env-tests.el

Another thing I'm trying to do is dump all the old third party code I had locally and, instead, use emacs' own package manager now. Currently this is also working well for me given that I'm using both ELPA and MELPA.

I haven't managed to dump everything yet, but it's a useful exercise to slowly work through the various files I was carting around and deciding if I need them or not (like, I'm fairly sure I won't be needing a cobol-mode any time soon -- that can go).

On top of all of this, on top of starting with a "clean slate" emacs, I've also started keeping track of what I do on GitHub. I've got a private repo for my ~/.emacs.d/ that I can now easily sync between my various machines.

One final thing that I'm starting to try and do is actually make full use of emacs again. One example is that I'm writing this blog post in it. Until now I've been using SublimeText with a Jekyll package to compose and manage things but, this time around I'm giving hyde and markdown-mode a go. So far they're working out pretty well too (albeit hyde was a bit odd to set up and isn't 100% making sense to me yet).


My first couple of weeks with an iMac

Posted on 2015-06-27 18:41 +0100 in Tech • Tagged with Mac, Apple, iMac, Unix, Emacs • 9 min read

My history with computers starts with a Sinclair ZX81 in the early 1980s, followed shortly by a Vic20, then on to the BBC B and fairly quickly on to very early IBM PC compatible machines. In the early 1990s I added OS/2 (during the introduction of Warp) and not too long after that GNU/Linux. Along the way I've also used the odd Unix here and there as well as CP/M, RSTS and VMS.

Aside from an inherited Mac whose model name escapes me, and whose operating system version also escapes me, I've never really had too much exposure to the world of Apple.

A couple of weeks back all of that changed.

It's quite a long time since I had a Unix of some form as a desktop machine and I was starting to get the urge to have one again. During all of this time I've had a GNU/Linux box or two available but for the past few years I've always used them from the (dis)comfort of my Windows desktop. Generally that was fine because the uses I had were not desktop.

Anyway, long story short: I started out thinking that I wanted some form of Unix on my desk again and, somehow, ended up walking out of a shop with an iMac.

Given the above history I thought it might be fun to jot down my experiences in the first couple of weeks. This will be a vaguely random wander through my experiences. It's not a review. It's not even really intended as a judgement of the machine and the operating system. It's nothing more than a collection of notes of what I found and my reaction to what I found.

The keyboard

The first strong reaction I had to the machine was regarding the keyboard. I thought I was going to hate it. I've had the misfortune of using various chiclet keyboards over the years and I've hated every single one. I find that I can't type on them, that it doesn't feel right, and that it makes my fingers ache badly if I spend too much time using them. My history and experiences has always been such that I've generally preferred very mechanical-feeling keyboards.

This just wasn't the case with the iMac keyboard. I don't know why, I still don't know why, but this feels like one of the most comfortable keyboards I've ever typed on. Despite the keys being chiclet style they move in a very positive way that really surprised me. It doesn't hurt to type, at all, and I'm finding I can type faster on this keyboard than any other I've typed on before.

There is a flipside though. I find the whole design far too cramped. Even now, a couple of weeks later, as I type this on it, I wish the keys were just a little bigger and just a little more spaced out. I'm adjusting, of course -- much of this is about muscle memory -- but it does mean that it's in a constant fight with my "knowledge" of my other main keyboards.

And then there's the keys that it lacks.

I'm still finding that this is a terrible keyboard for a programmer. For one thing, here on the UK version of the keyboard, there's no # key. At least, there's no simple, comfortable, direct access to the # key. Any time I want to type a # I have to shift my left hand to find the (I think it's called the) option key and hit 3. Shift 3 is £. And it gets even worse. This setup doesn't work at all in GNU emacs so I then have to put the keyboard in Australian mode so I can use shift-3 to get a #.

Why there isn't a proper # key is beyond me.

And then there's the (on the version that came with this iMac) complete lack of page keys as well as home and end. Overall this makes the whole keyboard feel very unfriendly to programmers and also to writers in general.

This, of course, is my bias and muscle memory from PCs showing. I'm still not convinced that that bias and muscle memory is wrong.

The mouse

When I first started with it I hated the mouse. I should be fair and point out that, overall, I hate mice anyway. For a good 20 years I've thrown away every mouse I've ever had turn up with a machine and have made use of a trackball instead. I find that a trackball gives me far more control and is far more comfortable. So, initially, I put the Apple mouse to one side and plugged in a trackball instead.

For reasons I forget now I found myself needed to use the Apple mouse again. Once I did that I decided to "force" myself to give it a fair shot and, now, I'm glad I did. Much like with the keyboard, despite me having a bias against what it is, this has turned out to be one of the most comfortable mice I've ever used. It sits right in the hand, the lack of actual buttons means I don't have to shape my hand to fit the design but, instead, the design allows for how my hand rests. I also rather like the gestures too.

This is the first mouse that has stayed on my desktop. I'm surprised.

By the way, whoever thought that the "natural" scroll option, which is on by default, was "natural", is barking mad.

The GUI

One of the main intended uses for this machine is the Unix shell, working inside the terminal. Given that the actual UI of the OS doesn't matter so much to me. That said, I'm finding it pretty pleasant. I find it a lot tidier-looking than Windows, although I also find it more frustrating in some places.

One good example is in the Finder, when I have a folder open. I find that it's quite common for me, on Windows, when I have an Explorer window open, to want to copy the path of the folder for use elsewhere. That's very easy to do because the path is in an edit field at the top of the window and can be edited and copied. If there's a way to do this with the OS X Finder I've yet to figure that one one.

Another thing I'm still not getting used to, and I'm still very unconvinced by, as a design decision, is the business of having an application's menus always appear at the top of the screen disconnected from the application windows themselves. I appreciate that this is a very Apple/Mac way of doing things but I really can't get used to the idea -- especially given that it gives the (incorrect) impression that the whole GUI is really single tasking.

On the whole though most of this doesn't matter too much to me. Large parts of what I'm doing is in the terminal window, with other parts of it being in my editors of choice (either SublimeText or GNU emacs, depending on what I'm doing) or inside Google Chrome. In other words the general experience is one that carries over most of the main operating systems I've used on desktop machines.

Installing software

For an operating system that prides itself on being simple to use and easy to understand, and especially one whose bigger fans sell as being simple to use and easy to understand (especially in relation to Windows), the whole business of installing software seems very confusing and very scrappy.

So far I've found a few different ways of installing software and none of it makes a whole lot of sense to me without going and searching about it and reading up on it. Sometimes I download an app and all I need to do is drag it into the Applications folder. Other times I get a zip which I have to open and then... it can go a couple of different ways. Sometimes I get a 'dmg' and when I open that up I get a window where I have to drag one icon onto another icon in that window to do the install. Sometimes I get something like the last one I mention but instead I have to double-click on an icon that's in the window.

There might even be other options I've had to follow. I forget now.

And then there's the business of removing software! That seems to be complete chaos. In some cases you delete the app and it's all good. In other cases you need to do that and hunt down some other bits and remove them too. In other cases it seems like the author has supplied their own uninstaller.

We've been here before. I know this setup rather well. This is exactly the sort of world we lived in back when Windows 3.1 was a new thing. This came as and still is a massive surprise to me: OS X is as sophisticated as a fancy shell that ran on top of MS DOS when it comes to software management.

Doing the right thing, except when not

While I'm on the subject of the famous great design of the Mac... what's up with the business of seeing the time format? The system preferences seem very flexible when it comes to setting date and time formats. I really like the dialog that provides this:

Setting the date format

As you might see above, my preference when it comes to date formats is to have everything in ISO 8601 format. Having set that I then noticed that the time shown in the menu bar on the desktop was.... whatever the hell Apple appear to have decided for me!

This is not the date format I asked for

Even Windows lets me set the date format as I want it in the desktop time display. Apple, meanwhile, seem to provide a great method of letting you set your date and time formats "just so" and then they seem to just go right ahead and ignore your preference in the one place you'll see it the most.

If you have a Mac, you have software I wrote on it (I think)

From what I could tell every Mac has a copy of GNU emacs installed, out of the box. That actually kind of impressed me. Sure, it's a rather out of date version of GNU emacs, but it's a copy of GNU emacs and that's all that matters.

It's a GNU emacs!

That fact actually means something rather interesting, to me. See, there's two small packages that are part of GNU emacs that I originally wrote. One is called 5x5, the other quickurl.

My rubbish claim to fame

So, yeah, from what I can see, on every new Mac you'll find two bodies of code that I originally wrote, pre-installed.

Yeah, I know, shitty claim to fame. I'll take it anyway. ;)

Overall initial impression

Overall my initial impression is a good one. The Apple iMac seems to make for a pretty good Unix workstation. The keyboard layout could do with some work to make it more friendly to programmers (well, to this programmer) but overall it all makes sense and is easy to navigate.

If most of what you do is actually online then I'd say that an iMac would be a huge waste of money. If you want a desktop machine for web browsing and generally working "in the cloud" then you'd do a lot better to buy a Chromebase (or, of course, a Chromebook if you're looking at Macbooks). On top of this, if most of what you're doing is online but you want to do some client-side stuff such as image/video editing and gaming then I struggle to see how an iMac would be a good choice too. For the money it's hilariously underpowered when compared to a reasonably equivalent Windows PC (or, of course, GNU/Linux machine if what you want to do can be done there).

My own reasons for purchase were about having a desktop Unix workstation that I could install various compilers on so I could muck about and work on some fun projects I want to get done. It was an unusual extravagance that I don't regret and, so far, I've been pleased with.

There's very few people I'd actually recommend one to though as it seems pretty clear to me that, generally, their money could buy them so much more.

But it's a nice new shiny toy. ;)