Skip to content

Commit

Permalink
Add support for multiple units
Browse files Browse the repository at this point in the history
  • Loading branch information
Atreyagaurav committed Aug 27, 2022
1 parent 6be0385 commit 01a4960
Show file tree
Hide file tree
Showing 3 changed files with 114 additions and 24 deletions.
50 changes: 46 additions & 4 deletions README.org
Original file line number Diff line number Diff line change
@@ -1,16 +1,38 @@
* units-global-mode
* units-mode

This mode uses [[https://www.gnu.org/software/units/units.html][gnu units]] to facilitate unit conversions inside emacs.

*This package is a work in progress*

* Contents :TOC:
- [[#units-mode][units-mode]]
- [[#features][Features]]
- [[#installation][Installation]]
- [[#examples][Examples]]
- [[#simple-conversion][Simple conversion]]
- [[#derived-units][Derived units]]
- [[#multiple-units][Multiple units]]

* Features
- [X] convert region to other units
- [ ] check ~--conformable~ units
- [X] check ~--conformable~ units for completion

* Installation
First clone this repo into your local machine, then you can load it.

An example config using ~use-package~ is like this:

#+begin_src emacs-lisp
(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))
#+end_src

* Example

* Examples
** Simple conversion
If you have

L = 23 ft
Expand All @@ -19,13 +41,33 @@ And you ran ~units-convert-region-and-insert~ while selecting ~23 ft~ you'll be

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

Similarly,

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

There is completion for the target unit, that is non-exhaustive as it only includes defined units and not derived ones like ~ft/s^2~
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
49 changes: 39 additions & 10 deletions tests/units-tests.el
Original file line number Diff line number Diff line change
Expand Up @@ -2,15 +2,44 @@

;; conversion tests
(ert-deftest units-convert-single-test ()
(should (= (units-convert-single 10 "ft" "m") 3.048))
(should (= (units-convert-single 1 "m" "ft") 3.2808399))
(should (= (units-convert-single 1 "kg" "g") 1e3))
(should (= (units-convert-single 1 "hour" "seconds") (* 60 60)))
(should (= (units-convert-single 1 "day" "hour") 24)))
(should (= (string-to-number
(units-convert-single 10 "ft" "m")) 3.048))
(should (= (string-to-number
(units-convert-single 1 "m" "ft")) 3.2808399))
(should (= (string-to-number
(units-convert-single 1 "kg" "g")) 1e3))
(should (= (string-to-number
(units-convert-single 1 "hour" "seconds")) (* 60 60)))
(should (= (string-to-number
(units-convert-single 1 "day" "hour")) 24)))

(ert-deftest units-convert-test ()
(should (= (units-convert "10ft" "m") 3.048))
(should (= (units-convert "1 m" "ft") 3.2808399))
(should (= (units-convert "1kg" "g") 1e3))
(should (= (units-convert "1 hour" "seconds") (* 60 60)))
(should (= (units-convert "1 day" "hour") 24)))
(should (= (string-to-number
(units-convert "10ft" "m")) 3.048))
(should (= (string-to-number
(units-convert "1 m" "ft")) 3.2808399))
(should (= (string-to-number
(units-convert "1kg" "g")) 1e3))
(should (= (string-to-number
(units-convert "1 hour" "seconds")) (* 60 60)))
(should (= (string-to-number
(units-convert "1 day" "hour")) 24))
(should (string= (units-convert "1.5 day" "day;hour") "1;12"))
(should (string= (units-convert ".5 day" "day;hour") "0;12")))

(ert-deftest units-convert-formatted-test ()
(should (string=
(units-convert-formatted "10ft" "m") "3.048 m"))
(should (string=
(units-convert-formatted "1 m" "ft") "3.2808399 ft"))
(should (string=
(units-convert-formatted "1kg" "g") "1000 g"))
(should (string=
(units-convert-formatted "1 hour" "seconds") "3600 seconds"))
(should (string=
(units-convert-formatted "1 day" "hours") "24 hours"))
(should (string=
(units-convert-formatted "1.5 day" "day;hours")
"1 day + 12 hours"))
(should (string=
(units-convert-formatted ".5 day" "day;hours") "12 hours")))
39 changes: 29 additions & 10 deletions units-mode.el
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@
;; This is emacs interface to gnu units program <https://www.gnu.org/software/units/units.html>.

;;; Code:
(require 'cl-lib)

(defcustom units-binary-path "units"
"Path to the units binary.")
Expand Down Expand Up @@ -56,15 +57,34 @@
value)))

(defun units-convert (value to-unit)
(let ((out-lines (split-string (string-trim-right (units-command value to-unit)) "\n")))
(let ((out-lines (split-string
(string-trim-right
(units-command value to-unit)) "\n")))
(if (length= out-lines 1)
(string-to-number (car out-lines))
(car out-lines)
(user-error "%s" (string-join out-lines "\n")))))

(defun units-convert-single (value from-unit to-unit)
(units-convert (format "%s %s" value from-unit) to-unit))


(defun units-convert-formatted (value to-unit)
(let ((converted (units-convert value to-unit)))
(if (cl-search ";" to-unit)
(let ((values (split-string converted ";"))
(units (split-string to-unit ";")))
(string-join
(cl-loop for val in values
for unt in units
if (> (string-to-number val) 0)
collect (format "%s %s" val unt)) " + "))
(format "%s %s" converted to-unit))))

(setq values (split-string "1;0;1" ";"))
(setq units (split-string "m;cm;mm" ";"))



(defun units-conformable-list (value)
(split-string
(string-trim
Expand All @@ -79,7 +99,7 @@
(completing-read
"Convert to: "
(units-conformable-list region-text)))))
(message "%s" (units-convert region-text to-unit)))
(message "%s" (units-convert-formatted region-text to-unit)))

(defun units-convert-region-and-insert (region-text to-unit)
(interactive
Expand All @@ -90,13 +110,12 @@
(completing-read
"Convert to: "
(units-conformable-list region-text)))))
(save-excursion
(goto-char (region-end))
(insert (concat " = "
(number-to-string
(units-convert region-text to-unit))
" "
to-unit))))
(goto-char (region-end))
(insert (concat " = "
(units-convert-formatted region-text to-unit))))

(define-minor-mode units-mode
"Minor mode for Calculations related to units.")

(provide 'units-mode)

Expand Down

0 comments on commit 01a4960

Please sign in to comment.