Conversions 10a.zip (13.3 KB)
ABOUT
This package contains two macros that call the same Perl script to convert from one unit of measure to another or perform a caluation on a selection when you press the trigger key.
In the text editor version, the trigger key is Control-Option-Equals. In the browser version, which is intended for a palette, the trigger key is the Equals sign.
INTRO
Once upon a time Peter Lewis wrote a macro called Calculate Macro (Calculate Macro) that would return the result of an equation if you preceded it with a particular (and unique) string of characters.
I liked that idea. I'd been using a service and then Spotlight to do that. But, as with so many other things, Keyboard Maestro was able to replace those approaches.
But I preferred triggering the function on a selection rather than a typed string. That allows me to revise the calculation endlessly before selecting it and getting the result. I could even undo the calculation to make more edits.
Then I thought why restrict it to just a calculation? Why not do some common conversions that slow me down in the press releases I edit.
So I expanded the macro to handle those too. But there were a lot of them and the visual nature of Keyboard Maestro's programming tools made it hard to see which branch of an if-else action I was in.
So I just rewrote the thing in Perl.
I set the macro to run when you type Control-Option-Equals on a selection. And made it active in my text and word processing applications. The idea was to replace the selection with the conversion.
But then I starting wishing I had access to it when Web browsing to convert unfamiliar metric measurements into more familiar imperial ones. How far is 1,300km? Oh, it's 808 miles.
So I wrote a version for my Safari palette (which is why the trigger is just one character, so beware) which also works in other browsers (Chrome, Firefox and Vivaldi were tested) that reads a selection and pops up a dialog with the conversion, while putting the conversion on the System Clipboard in case I want to paste it somewhere, too.
That's why there are two of these.
INSTALLATION
But they both use the same 104 lines of Perl code. No sense repeating that in each macro when the Execute Shell Script can reference an external file.
And with a little test at the top of that Perl file, we can run the same code either within a Keyboard Maestro macro or as a BBEdit/TextWrangler text filter.
Which is why there are three other files (including this one) in this distribution.
Put the Conversions.hybrid.pl Perl file in your text filters folder or anywhere you like and point Execute Shell Script in the two macros to it. You're set for life.
You might be interested in a couple of other changes.
You could just copy the Conversions.hybrid.pl file into the Execute Script action instead of keeping a copy outside Keyboard Maestro. If you do that, you can change the test at the top to the simple assignment:
$str = $ENV{KMVAR_kmVar};
If you are using the browser macro, you could also eliminate the JavaScript by having the Execute Shell Script action display the results briefly or in a window, if you prefer. We're using JavaScript in the browser version because we prefer the look of its dialog.
DEFAULT CONVERSIONS
The conversions, based on formulas from CEVA (http://www.cevaground.com/Customers/Conversions/ConversionFormula.aspx). Conversions, are handled in three groups. First we handle an aspect ratio conversion for embedded videos (just to get that out of the way) which I find useful. Then we handle calculations, keeping them distinct from the main body of conversions, which is the third group.
Conversions in the third group can go both ways. You can select someting in centimeters to get inches and something in inches to get centimeters, for example. Whitespace is adroitly handled so that 10km and 10 km are equally understood (although one is bad form).
The default conversions include:
-
That esoteric width/height conversion that calculates the correct heights for two of my preferred widths, useful for embedding videos. Any width other than 500 is set to 500 before the height is calculated but any 500 pixel width is set to 480 before the height is calculated. So if I need a 480px wide video, I just run the thing twice.
-
Any selection with an operator (+ - / *) is calculated. Parentheses will also trigger a calculation.
For example, "abs(-5)" will return "5" and log(2.71828183)" will return "1.00000000056689." -
Common conversions, the meat of this dish, include:
cm - inches
mm - inches
g - ounces
kg - pounds
m under 100 - feet
m over 100 - yards
km - miles
°C - °F
NB: Inches and feet are converted from " and ' symbols but not to them.
Only the degree symbol (Shift-Option-8) and not the masculine ordinal (Option-0) will trigger temperature conversions (see https://www.howtotype.net/symbol/Degree_symbol/). If the academic space is used, it will be maintained. Varied results on the Web (Weather Underground (https://www.wunderground.com) works, local news sites don't).
Commas are legal in selections but stripped before any calculations are done. But persist in the original selection.
Any selection not converted will be returned unharmed to your text.
CURRENCY
Due to constantly varying rates, this macro does not attempt currency conversion.
REPEAT ORIGINAL VALUE
If you wish to repeat an original value (other than a width/height conversion or a calculation) in parentheses, simply include a trailing space at the end of your selection.
For example, selecting '12 lbs. ' will return '5.44kg (12 lbs.) ' with the trailing space.
EXAMPLES
I debugged the Perl code in TextWrangler where I was able to throw a variety of data at it to see what happens. The data and the results shown below are delimited by single quotes:
Embedded video resizing:
'width="560" height="315"' = 'width="500" height="281"'
'width="500" height="281"' = 'width="480" height="270"'
Calculations:
'(1+2+3)/3' = '2'
'log(2.71828183)' = '1.00000000056689'
'abs(-10) + abs(10)' = '20'
Conversions:
'50cm' = '19.68 in.'
'12g' = '0.42 oz.'
'12 lbs.' = '5.44kg'
'24gm' = '0.84 oz.'
'67mm' = '2.63 in.'
'12g ' = '0.42 oz. (12g) '
'12 lbs. ' = '5.44kg (12 lbs.) '
'24gm ' = '0.84 oz. (24gm) '
'67mm ' = '2.63 in. (67mm) '
'120kg' = '264.00 lbs.'
'110m' = '120 yards'
'12m' = '39.37 ft.'
'80km' = '50 miles'
'120 ft' = '40.00 yards'
'20 in.' = '50.80cm'
'120'' = '40.00 yards'
'20"' = '50.80cm'
'42 oz.' = '1.19kg'
'120 yards' = '110m'
'50 miles' = '80km'
'59°F' = '15°C'
'23°C' = '73°F'
'2300°K' = '2300°K'
'59 °F ' = '15 °C (59 °F) '
'15°C ' = '59°F (15°C) '
'79 °F' = '26 °C'
'17 °C' = '63 °F'
Not Converted:
'log(2.71828183) ~ 1.00' = 'log(2.71828183) ~ 1.00'
'23 tons' = '23 tons'
ROLL YOUR OWN
You can add your own conversions to the Perl script. There are two places to check in any particular group.
The first is in the if-elsif regex that defines the group. Make sure your label or symbol is included. For the common conversions section of the Perl code, you would look at:
} elsif ($str =~ /([\.\d]+?) ?([a-z'"]+?\.?) ?$/) {
to confirm it will recognize your label. For example, we had to add the quote marks to handle common foot (') and inch (") labels. But "ml" would already be included in the "a-z" range.
After confirming your label will be recognized, add an elsif statement in that section of the group's code using the following template:
} elsif ($str =~ /[search string]/) {
$ans = eval($calc * [conversion value]);
$ans = sprintf("%.2f [converted label]",$ans);
where:
-
[search string] is a regex for what you're looking for
-
$calc * [conversion value] is the conversion formula
-
%.2f [converted label] is the output format (here with two decimals)
You'll need one more of these to convert back, of course.
I have them collected in imperial and metric sections but you can organize them however you like, the code doesn't mind.
How do you know when to create a new group?
The groups cascade from longer regex descriptions to shorter ones. In fact, some of the longer ones would be processed by the short one if we didn't trap it earlier. They aren't mutually exclusive.
So if you wanted to look for cubic inches or liquid ounces, which would require a double label, you'd want to put that above the third group that does most of the work. The regex that would describe that group would include both labels and safely handle the conversion before the third group got its hands on it.
SUPPORT
I'm happy to promptly address any concerns you may have.