Atom is Dead! Long Live Atom!
5 Jun 2018
Yesterday, Microsoft announced it’s acquiring GitHub. *Cue Wilhelm Scream* While I wasn’t around for the “Embrace, Extend, Extinguish” Era of Microsoft, I can say that I’m not a fan of how paid products (e.g. Windows) are treated as an advertising platform. I’m not worried about Open Source in general, as repositories can easily be pushed to GitLab, BitBucket, or any number of GitHub-esque services. What I am worried about though, is my faux-IDE and GitHub-owned text editor, Atom. Among the many contenders in the great text editor wars, such as Vim, Emacs, and Sublime, is Visual Studio Code. Built on Electron, VS Code is customizable and extensible through packages, much like Atom, and is owned by Microsoft. Even though parts of Atom are built on top of Microsoft technology, namely the Language Server Protocol, is Microsoft really willing to split engineering resources across two competing products? Maybe, but regardless of the answer, I’m not worried about Atom (as you may have guessed from the title). Atom, remember, is open source. It’s just another repository hosted on GitHub. If things go south, it can be forked and pushed to any of the aforementioned “GitHub-esque” services, and development can continue right along. Without the backing of GitHub, development would most likely slow, but will not grind to a halt.
Of course, that’s a worst-case scenario. As far as they go though, it’s not bad. We could get lucky though, and see Atom development continue right along as usual, maybe with even a bit more wind behind its sails.
Roll Your Own Python IDE, Part Deux
17 May 2018
It’s been one year since I attempted to cobble together a Python IDE with Atom, and surprise! It’s still here. A lot has changed though, to say the least, so I thought I’d take a moment to share my current setup.
Atom IDE
Some higher-ups at Facebook must have read my first post because a few months after GitHub announced Atom-IDE, a set of extensible packages designed to bring IDE-like functionality to Atom (alas, Python was not on the list of initially-supported languages, but was mentioned as hopefully coming soon). It initially boasted features such as autocomplete, diagnostics, find all references, go to definition, hover, and an outline view. That last feature was very much welcomed after being spoiled by Xcode.
Sure enough, less than two weeks later, ide-python appeared, providing Python support with atom-ide-ui and the Python language server. There are a variety of providers supplied by the Python language server, and it’s worth giving each a quick mention.
Jedi
No, not the Force-weilding guardians of peace, Jedi is a static analysis library that provides autocompletion suggestions (And hopefully linting and refactoring in the future).
Rope
I’m not going to rope you into suffering a horrible pun for every one of these. Rope provides refactoring, and can be configured on a per-project basis, with settings living in the .ropeproject folder at the root of your project.
Pyflakes
Pyflakes helps ensure your code doesn’t flake on execution (I’m so sorry) by parsing source files for errors.
McCabe
McCabe measures the cyclomatic complexity of source code. You hopefully shouldn’t be seeing too many warnings from this, but it’s nice to know it’s there.
pycodestyle
Formerly known as pep8, pycodestyle checks your code against the one true style convention, PEP 8
The quickest way to get up and running with ide-python is to install the atom package and its dependencies with:
pydocstyle
Pydocstyle is pycodestyle for documentation (Which I know you’re all including). I recommend adding “D100” to the list of warnings to ignore, thanks to numpy.
YAPF
YAPF (Yet Another Python Formatter), is yet another python formatter from Google. It’s based on clang-format, and is highly configurable. It fixes the problem of autopep8 and other formatters that only reformat code to make it PEP 8 compliant, and won’t touch compliant code, no matter how atrocious. To enable this glorious tool, you have to disable autopep8, as ide-python will prefer it over YAPF.
Installing up ide-python and its dependencies is pretty simple:
$
apm install ide-python atom-ide-ui
And then install the python language server with all supported features:
$
pip install 'python-language-server[all]'
Of course if you don’t want all of the features *cough* autopep8 *cough*, you can simply disable them in ide-python’s settings, or follow the official installation instructions to skip the unwanted providers.
Debugging
While the original DIY Python IDE did feature a debugger, it left much to be desired. Atom IDE has an excellent debugger module with Python support that integrates beautifully. Breakpoints can be set in the gutter, and controls are to the right of the editing area. Underneath is the console tab which supports REPL.
As you may have guessed, installation is a breeze:
$
apm install atom-ide-debugger-python
Atom’s customizability and extensibility gives it incredible potential, and IDE features are a tremendous example of the power of the platform. I’m excited to see where it will go in the future.
Context-sensitive scripting on macOS
19 Feb 2018
In last week’s Under the Radar, Marco and David expounded on the idea of second locations, something I am very familiar with as a frequent and reluctant resident of Laptop Land™. As old as it makes me feel (And I’m way too young to be saying that), I’m simply more productive in front of a desktop-like environment than hunched over a laptop. I also whole-heartedly agree with the idea that trying to bend a laptop into a desktop tends to give you the worst of both worlds. That being said, having a device with full-fledge operating system with me wherever I go has saved my skin too many times to count (Sorry Federico), and with a little scripting and the help of WatchPaths in launchd, I can make my MacBook behave more like a desktop when it’s docked at a desk, and behave like a MacBook when it’s not.
Below is a template for a generic launchd process that runs a script whenever a given file or folder is modified.
| <?xml version="1.0" encoding="UTF-8"?> |
| <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"> |
| <plist version="1.0"> |
| <dict> |
| <key>Label</key> |
| <string>com.name.of.process</string> |
| <key>ProgramArguments</key> |
| <array> |
| <string>/path/to/script</string> |
| </array> |
| <key>WatchPaths</key> |
| <array> |
| <string>/path/to/file/or/folder/to/watch</string> |
| </array> |
| <key>KeepAlive</key> |
| <true/> |
| </dict> |
| </plist> |
For example, as a wallpaper connoisseur, I use and can’t recommend Wallcat enough. It offers a fresh, curated wallpaper every day, with multiple channels to choose from to suite your taste. Another symptom of being a wallpaper connoisseur, I appreciate continuity across desktops when using multiple displays, so I wrote a short appleScript wrapped in a bash script that detects if my MacBook is connected to the dock at my desk, and quits Wallcat (Which is very *ahem* adamant, that its wallpaper is the one showing) and sets the wallpaper appropriately. The script is ran whenever a change to the display pane in System Profiler is detected. Is this the most elegant solution? No, but it is effective.
| #!/bin/bash |
| |
| externalDisplays=$(system_profiler SPDisplaysDataType | grep -c 'Name of displays') |
| |
| if [ "$externalDisplays" -eq 2 ] |
| then |
| osascript <<EOF |
| quit application "Wallcat" |
| tell application "System Events" |
| tell desktop 1 to set picture to "path/to/wallpaper/left.jpg" |
| tell desktop 2 to set picture to "path/to/wallpaper/right.jpg" |
| end tell |
| EOF |
| else |
| osascript <<EOF |
| if application "Wallcat" is not running then |
| tell application "Wallcat" to activate |
| end if |
| EOF |
| fi |
Once you’ve written your script and launchd plist, you’ll need to add the plist as either a LaunchDaemon or LaunchAgent. LaunchDaemons are loaded and can run during boot, while LaunchAgents are loaded at login, and can be user-specific. With that in mind, I made my wallpaper switcher a LaunchAgent local to my user account, seeing how it relies on files in my Pictures folder. LaunchDaemon plists live in /Library/LaunchDaemons
, LaunchAgents live in /Library/LaunchAgents
, and, shockingly, user-specific LaunchAgents are stored in ~/Library/LaunchAgents
. Make sure LaunchDaemons and non-user-specific LaunchAgents are owned by root. All plists belong in wheel, with 644 permissions. To load plists without needing to log out and log back in or restart:
$
sudo launchctl load /path/to/plist
To unload plists:
$
sudo launchctl unload /path/to/plist
LaunchDaemons and LaunchAgents are powerful tools for automating tasks and configurations depending on where you are and what you’re doing.