Trying out Perl packages locally

I’ve really enjoyed Perl since I started using it in late 2016. I invite you to experiment with it yourself! For trying out packages from CPAN (Perl’s package archive) on your local system, I suggest:

  1. Install local::lib per https://metacpan.org/pod/local::lib#The-bootstrapping-technique
  2. Install cpanminus. If it’s not a system package on your distro, follow https://metacpan.org/pod/App::cpanminus#Installing-to-local-perl-(perlbrew,-plenv-etc.) .
  3. say cpanm App::cpmcpm is faster than cpanminus 😀
  4. To install a module, say cpm -gv Whatever::Module

Yes, this is more tedious than I would prefer! I’m sure there are shorter ways that are distro-specific, but the above should work just about anywhere.

Some sites that can help you learn:

Dragging tabs off a Chromium window (solved!)

For several months, I have not been able to drag tabs off a Chromium window. When I let go of the mouse button to release the tab, Chromium didn’t respond. That is finally fixed!

First, thanks to jangxx for discovering that turning off Chromium’s “Use system titlebar and borders” option fixes the problem. Unfortunately, my Chromium doesn’t have that option! I had to do it by hand:

  1. In the browser, go to chrome:settings
  2. Under Appearance, make sure “Theme” is “GTK+”. If it’s not, hit “Use GTK+”.
  3. In the browser, go to chrome:version
  4. Make a note of the “profile path”.
  5. Exit Chromium entirely.
  6. In a shell, cd to the profile path
  7. cp Preferences Preferences.bak
  8. Edit Preferences and change "custom_chrome_frame":false to "custom_chrome_frame":true
  9. Restart Chromium. You should be able to drag tabs!

Let me know if this helps you, or if you need more information about these steps. Happy browsing!

autom4te and m4sh for the impatient

autom4te is the engine beneath autoconf, but you can use it to generate your own portable shell scripts for other purposes.  For example, create this test.m4sh:

# test.m4sh
m4_errprintn([before init])
AS_INIT
m4_errprintn([before copyright])
AS_COPYRIGHT([CC0])
AS_WARN([warning])
AS_ECHO([Hello!])

# draws a box on stdout
AS_BOX([Test foo])

# Puts a box in the output as a comment
m4_text_box([testing foo])

foo=1
AS_IF([test "x$foo" = 'x1'],[
echo Foo is 1
])
m4_errprintn([at end])

Run autom4te:

$ autom4te -l M4sh -Wall -o test.sh test.m4sh 
before init
before copyright
at end

(Note that the m4_errprintn calls print while autom4te is running.)

Now you have test.sh:

$ ./test.sh
test.sh: WARNING: warning
Hello!
## -------- ##
## Test foo ##
## -------- ##
Foo is 1

Stunning, right? 😉

The number one gotcha

If you forget AS_INIT, you will get no output and no error message.  You have been warned.

Commands used in this example

  • AS_INIT: required.  At the top of the input file.
  • AS_COPYRIGHT: puts the text you give it into the output as a comment at the top of the generated script file.
  • AS_WARN: prints a warning when the generated script runs
  • AS_ECHO: prints to stdout when the generated script runs
  • m4_errprintn: prints to stderr when autom4te runs.  No effect on the generated script.
  • AS_BOX: prints the “Test foo” box in the example output, when the generated script runs
  • m4_text_box: puts into the generated script file a comment like this one:
## ----------- ##
## testing foo ##
## ----------- ##
  • AS_IF: a shell conditional, but more portable.
  • test: the clunky, old-school (but very portable) way of checking conditionals.  For maximum portability, don’t let any argument to test be the empty string (hence the xs in the test command above)

Happy hacking!

Repeating the last ‘:’ (Ex) command in Vim

Sometimes I run a complicated search-and-replace (:s/../../) in Vim, and I then want to repeat it somewhere else. In the past, I have always hit :, up-arrow to retrieve the command from the history. It should be no surprise by now that there is an easier way!

@: in normal mode (at-sign, colon) will repeat the last : command. Once you have done @:, you can hit @@ to re-run the command. Quick and easy!

This works because the : register, ":, holds the last Ex command. @ runs a macro, and knows that using the : register means you want to repeat an Ex command. @@ runs the last macro, so works for @: just as it does for @a or any other normal-mode macro.

I found ": in :help registers when I was looking for a register that held the filename of the file open in another window, as opposed to the alternate filename in the current window. Details of ": are at :help ": (believe it or not! 😉 ).

Generating Roman numerals in Vala

I have recently been learning and enjoying the Vala programming language.  I am writing a lightweight markdown-to-PDF converter and wanted to be able to automatically number list items in Roman numerals.  Here, in case anyone wants it, is Knuth’s algorithm for producing the Roman numeral for a number.  I converted this to Vala from the original WEB source, part of TeX, as quoted by Hans Wennborg.  Enjoy!

string roman(uint num)
{
    // Knuth's algorithm for Roman numerals, from TeX.  Quoted by
    // Hans Wennborg at https://www.hanshq.net/roman-numerals.html.
    // Converted to Vala by Chris White (github.com/cxw42).  CC-BY 4.0 Intl.

    var sb = new StringBuilder();

    string control = "m2d5c2l5x2v5i";
    int j, k;   // mysterious indices into `control`
    uint u, v;  // mysterious numbers
    j = 0;
    v = 1000;

    while(true) {
        while(num >= v) {
            sb.append_c(control[j]);
            num -= v;
        }
        if(num <= 0) {  // nonpositive input produces no output
            break;
        }

        k = j+2;
        u = v / control[k-1].digit_value();
        if(control[k-1] == '2') {
            k += 2;
            u /= control[k-1].digit_value();
        }

        if(num+u >= v) {
            sb.append_c(control[k]);
            num += u;
        } else {
            j += 2;
            v /= control[j-1].digit_value();
        }
    }

    return sb.str;
} // roman()

(not extensively tested — use at your own risk. No warranty. License details here.)

Git internals for fun and profit

Just ran across this very enjoyable article about how GitHub sped up cloning by several orders of magnitude – https://github.blog/2015-09-22-counting-objects/.

If you haven’t seen it, check out the git commit graph.  In the Linux kernel tree, the time for me to show the commit graph of the five most recent commits went from five seconds to 20ms!  https://devblogs.microsoft.com/devops/supercharging-the-git-commit-graph/.  Requires Git 2.18+, which you can install on Ubuntu LTS from a PPA per this.  Short version:

git config --global core.commitGraph true

and then, in each repo:

git show-ref -s | git commit-graph write --stdin-commits

Vim tips: curly quotes and visual selection

Curly quotes: because reasons.  😉  In Insert mode:

  • Ctl+K '6 will give you an open curly single quote, and Ctl+K '9 will give you the closing curly single quote.
  • Similarly, Ctl+K "6 will give you an open curly single quote, and Ctl+K "9 will give you the closing curly single quote.

Visual mode: turns out you can just hit o when in Visual mode to move the cursor to the other end of the selection.  Handy!

Installing Elementary Files on Ubuntu 18.04 LTS

I learned about elementary OS from Slashdot.  I currently use Nautilus and xfe, but am not 100% happy with either.  I thought I would give Elementary Files (the elementary OS file manager) a try.

  • sudo apt-get install -y ninja-build gobject-introspection libgirepository1.0-dev
  • Uninstall meson if you have it installed (e.g., sudo apt remove meson)
  • pip3 install meson – you need at least v0.50 (I think).
  • Add ~/.local/bin to your PATH if you haven’t yet.
  • sudo apt-get install -y valac libcanberra-dev libdbus-glib-1-dev libgail-3-dev libgee-0.8-dev libglib2.0-dev libgtk-3-dev libnotify-dev libpango1.0-dev libplank-dev libsqlite3-dev libunity-dev libzeitgeist-2.0-dev
  • libcloudproviders-dev (bionic’s package isn’t new enough): git clone https://gitlab.gnome.org/World/libcloudproviders.git ; cd libcloudproviders ; git checkout 0.3.0 ; meson build ; cd build ; ninja && sudo ninja install
  • libgranite-dev (bionic’s package isn’t new enough): git clone https://github.com/elementary/granite.git elementary-granite ; cd elementary-granite/ ; git checkout 5.2.5 ; meson build ; cd build ; ninja && sudo ninja install
  • Files (at last!): git clone https://github.com/elementary/files.git elementary-files ; cd elementary-files ; git checkout 4.2.0 ; meson build ; cd build ; ninja && sudo ninja install

Whew!  This is reminding me why we have package managers 🙂 .

Let me know if this doesn’t work for you — I may have missed something by accident.

Word VBA: for speed, avoid Document.Paragraphs(idx)

In Word VBA, calling doc.Paragraphs(idx) to get a paragraph by its index is very slow.  Instead, once you have a Paragraph object, use para.Next and para.Previous to navigate, and your code will be much faster!  I just refactored an old routine this way and received a dramatic speedup.

I think doc.Paragraphs() must be iterating through the document starting from the beginning, but I don’t know that for sure.  I do know that adding paragraphs before the region my code was working with made the code run perceptibly slower, even though the code was never touching the added paragraphs.

Here are some simple helpers, in case you want to manually check for errors rather than throwing when you run off the end of the document:

Private Function NextParaOrNothing_(p As Paragraph) As Paragraph
    Set NextParaOrNothing_ = Nothing
    On Error Resume Next
    Set NextParaOrNothing_ = p.Next
End Function 'NextParaOrNothing_

Private Function PrevParaOrNothing_(p As Paragraph) As Paragraph
    Set PrevParaOrNothing_ = Nothing
    On Error Resume Next
    Set PrevParaOrNothing_ = p.Previous
End Function 'PrevParaOrNothing_

 

Fixed: the SSD freezing my computer!

My new Samsung SSD was causing strange lockups. Everything worked fine during the lockups except for disk activity. I found https://odd.blog/2013/11/26/yes-finally-fixed-ssd-freezing-computer/, which gave me a fix: make sure the IDE drivers are enabled, then change the drive mode from AHCI to IDE. It’s been a week or two problem-free!

Samsung 860 EVO

Biostar A960D+ mobo (AMD chipset, which is apparently the issue.)