/units-mode

Unit conversion in emacs using gnu units

Primary LanguageEmacs LispGNU General Public License v3.0GPL-3.0

https://melpa.org/packages/units-mode-badge.svg https://stable.melpa.org/packages/units-mode-badge.svg

Introduction

This mode uses gnu units (which you need to install) to facilitate unit related conversions/calculations inside emacs.

I wrote units-mode so that I can do quick conversion and see the values, as well as get possible units as completion to choose from so I know which units are similar. And gnu units being lot more powerful for units, you’ll get the full power of gnu units inside emacs.

Emacs supports unit conversion in =calc= by default, so if you use calc then you can do conversions there too however units-mode will make the conversion available anywhere, and easily callable functions to convert for your packages too.

This package is a work in progress it may not handle all the errors or perform all the checks yet.

Contents

Features

  • convert region to other units (e.g 1 mile ⇒ 5280 ft)
  • check --conformable units for completion
  • Early error out for non-existent units
  • Errors out when target unit isn’t the same dimension
  • reduce expressions to standard unit form (e.g 1ft + 12 inch ⇒ 0.6096 m)
  • Calculate molecular weight from chemical formula (e.g. CH3 ⇒ 15.03482)

Installation

First clone this repo into your local machine or install it from melpa, then you can load it.

An example config using use-package is like this:

(use-package units-mode
  ;; :load-path "/path/to/units-mode"
  :hook text-mode
  :config
  (local-set-key (kbd "C-c u") 'units-convert-region-and-insert))

Customizations

customize variables

Available variables to customize are:

  • units-binary-path [default: “units”] “Path to the units binary.”

    Change this if units isn’t in your path, it should point to the units binary

  • units-user-args [default: “”] “Extra args for user to add to units command.”

    If there is any args necessary for user. Default arg used by system is “-t” to get terse results so it depends on that to parse the results. Look at man units for possible args.

  • units-insert-separator [default: ” = “] “Separator to insert before inserting the `units’ outputs.”

    When using the convert and insert variety of functions the converted value is separated with this separator before being inserted. for eg 1 m = 3.2808399 ft.

Keybindings

feel free to set your own keybindings, example is shown in Installation. The functions you can bind are in Interactive Functions.

Interactive Functions

  • units-convert-region Convert the marked region to a unit by asking units interactively. The interactive prompt has completions for defined units with same dimension but complex ones can be entered too.
  • units-convert-region-and-insert Convert region to unit and insert the results. Same as units-convert-region but insert the results.
  • units-reduce-region Reduce the region to standard units.
  • units-reduce-region-and-insert Reduce the region to standard units and insert the results.
  • units-quick-convert Quickly convert an expression into a unit interactively.

Examples

Simple conversion

If you have

L = 23 ft

And you ran units-convert-region-and-insert while selecting 23 ft you’ll be asked for target unit and with mm you get:

L = 23 ft = 7010.4 mm

There is completion for the target unit, that is non-exhaustive. So feel free to type whatever unit you want to. But pressing tab will help you see some of them.

Derived units

Similar to previous, you can use derived units that are product of other units, or expression with numbers with units.

g = 9.81 m/s^2
g = 9.81 m/s^2 = 32.185039 ft/s^2

and,

g = 9.81 m/s^2 + 12 N / 4kg
g = 9.81 m/s^2 + 12 N / 4kg = 42.027559 ft/s^2

do note that the expression needs to be valid, if you try 1m + 2 gram You’ll get error.

Completion only includes defined units and not derived ones like ft/s^2, so you need to type it fully.

Running units-convert-region will just show the converted results in the minibuffer.

If there is errors, like units aren’t matched then it’ll end with the error from units

Multiple units

Since units can allow you to convert to multiple units, this package also can.

For example using ft;in in 1m here returns this:

L = 1m
L = 1m = 3 ft + 3.3700787 in
L = 1m = 3 ft + 3.3700787 in = 100 cm

As you can see in the third line, you can use that value again to convert to something else as units supports simple calculations on units.

Also note that it’ll remove the unit with 0 coefficient, for example converting 1mile to ft;in will result in this:

L = 1mile
L = 1mile = 5280 ft

Reduce to standard units

You can reduce a expression to standard units, for example running units-reduce-region-and-insert on region after = in these examples we get:

L = 1 miles
L = 1 miles = 1609.344 m
g' = 1.9 force
g' = 1.9 force = 18.632635 m / s^2
area = 5 acre
area = 5 acre = 20234.282 m^2

Package Functions to use in your code

Elisp

You can load and then directly use the functions in your code. Most useful ones are:

(list (units-convert-simple (/ 1.0 2) "m" "ft")
      (units-convert "2 m" "ft")
      (units-reduce "1 m + 24 in")
      (units-ignore 5 "ft"))
1.64041996.56167981.6096 m5

Slime Integration (example is for sbcl; adapt to whatever clisp you use)

Although not part of emacs package there is a file clisp/units.lisp with functions that do similar things in sbcl. You can load/evaluate the functions there in slime process to use those same functions in slime.

You can also put the contents in clisp/units.lisp to ~/.sbclrc so it’s evaluated in sbcl startup, similarly for any other dialect you use.

The slime integration means you’ll have advantages of clisp rational numbers and other things while using the same syntax as that of elisp.

Same example using sbcl. (Note that here you don’t have to use 1.0/2 coz 1/2 ≠ 0 in sbcl)

(list (units-convert-simple (/ 1 2) "m" "ft")
      (units-convert "2 m" "ft")
      (units-reduce "1 m + 24 in")
      (units-ignore 5 "ft"))
1.64041986.561681.60965