Code Monkey home page Code Monkey logo

corpus's Introduction

"dotfiles" and system configuration

These dotfiles are affectionately dedicated to the vi editor originally created by Bill Joy, with whom I have spent many pleasant evenings1

โ€” Greg Hurrell, paraphrasing Donald Knuth

Overview

Features

Dotfiles

A set of dotfiles that I've been tweaking and twiddling since the early 2000s (under version control since 2009). Characteristics include:

  • Sane Vim pasting via bracketed paste mode.
  • Write access to local clipboard from local and remote hosts, inside and outside of tmux (via Clipper).
  • Full mouse support (pane/split resizing, scrolling, text selection) in Vim and tmux.
  • Focus/lost events for Vim inside tmux.
  • Cursor shape toggles on entering Vim.
  • Italics in the terminal.
  • Bundles a (not-excessive) number of useful Vim plug-ins.
  • Conservative Vim configuration (very few overrides of core functionality; most changes are unobtrusive enhancements; some additional functionality exposed via <Leader> and <LocalLeader> mappings.
  • Relatively restrained Zsh config, Bash-like but with a few Zsh perks, such as right-side prompt, auto-cd hooks, command elapsed time printing and such.
  • Unified color-handling (across iTerm2 and Vim) via Base16 Shell.
  • Encrypted versioning of files with sensitive content (via git-cipher).
  • Comprehensive Hammerspoon config.

Homebrew

On macOS, the "homebrew" aspect installs a bunch of useful software.

Keyboard customization

On macOS, we use Karabiner-Elements, and on Linux, we use Interception Tools and a few other pieces to make the following changes:

  • Make Caps Lock serve as Backspace (when tapped) and Left Control (when chorded with another key). When held down alone, Caps Lock fires repeated Backspace events.
  • Make Return serve as Return (when tapped) and Right Control (when chorded with another key). When held down alone, Return fires repeated Return events.
  • Toggle Caps Lock on by tapping both Shift keys simultaneously.
  • Makes the function keys on my external Realforce keyboard behave like the "media" keys on Apple's keyboards.

And these only on macOS:

  • Swap Option and Command keys on my external Realforce keyboard.
  • Make the "application" key (extra modifier key on right-hand side) behave as "fn" on Realforce keyboard.
  • Map Control-I to F6 (only in the terminal) so that it can be mapped independently from Tab in Vim2.
  • Make "pause" (at far-right of function key row) behave as "power" (effectively, sleep) on Realforce keyboard.
  • Adds a "SpaceFN" layer that can be activated by holding down Space while hitting other keys; I use this to make the cursor keys available on or near the home row in any app.

Zsh

Functions

  • ag: Transparently wraps the ag executable so as to provide a centralized place to set defaults for that command (seeing as it has no "rc" file).
  • bounce: bounce the macOS Dock icon if the terminal is not in the foreground.
  • color: change terminal and Vim color scheme.
  • fd: "find directory" using fast bfs and sk; automatically cds into the selected directory.
  • fh: "find [in] history"; selecting a history item inserts it into the command line but does not execute it.
  • history: overrides the (tiny) default history count.
  • jump (aliased to j): to jump to hashed directories.
  • regmv: bulk-rename files (eg. regmv '/\.tif$/.tiff/' *).
  • scratch: create a random temporary scratch directory and cd into it.
  • tick: moves an existing time warp (eg. tick +1h); see tw below for a description of time warp.
  • tmux: wrapper that reattches to pre-existing sessions, or creates new ones based on the current directory name; additionally, looks for a .tmux file to set up windows and panes (note that the first time a given .tmux file is encountered the wrapper asks the user whether to trust or skip it).
  • tw ("time warp"): overrides GIT_AUTHOR_DATE and GIT_COMMITTER_DATE (eg. tw -1d).

Prompt

Zsh is configured with the following prompt:

Visible here are:

  • Concise left-hand prompt consisting of:
  • Extended right-hand size prompt which auto-hides when necessary to make room for long commands and contains:
    • Duration of previous command in adaptive units (seconds, minutes, hours, days, depending on duration).
    • Current version control branch name.
    • Current version control worktree status using colors that match those used in git status:
      • Green dot indicates staged changes.
      • Red dot indicates unstaged changes.
      • Blue dot indicates untracked files.
    • Full version of current working directory (again, abbreviating $HOME to ~).

Nested shells are indicated with additional prompt characters. For example, one nested shell:

Two nested shells:

Root shells are indicated with a different color prompt character and the word "root":

Nesting within a root shell is indicated like this:

Two nested shells:

If the last command exited with a non-zero status (usually indicative of an error), a yellow exclamation is shown:

If there are background processes, a yellow asterisk is shown:

Dependencies

  • tmux 3.2 or later.
  • Neovim v0.5.0 or later.
  • Relatively recent Zsh.
  • Relatively recent Git.
  • Clipper for transparent access to the local system clipboard.
  • On macOS, iTerm2 or Kitty. Additionally, only the latest one or two versions of macOS (at the time of writing, that means Sonoma) get actively tested.
  • Ruby.
  • Adobe Source Code Pro or any other fixed-width font that includes the Powerline glyphs.

Platform status

Platform Status
macOS ๐Ÿฅ‡ Currently the most tested platform, as well as the one with most aspects (because my daily driver is macOS 13 "Sonoma")
Debian(-ish) Linux ๐Ÿฅˆ I use this heavily at work, but in the somewhat odd Codespaces VM environment, so there are some weird assumptions at play
Arch Linux ๐Ÿฅ‰ Less tested, fewer aspects involved, but likely to evolve in the future as I'm using Arch Linux on my "leisure" desktop machine
Red Hat Linux and related (eg. CentOS) ๐Ÿ’€ Abandoned, but in the past (2011-2018) this was the distro I used full-time at work

Installation

Clone

Development occurs on the main branch, but to avoid inconvenience for people who previously cloned the repo when the master branch was the main line, the legacy branch is kept up-to-date via a pre-push hook (which updates the local branch) and a post-receive hook (which updates the remote).

macOS

git clone --recursive https://github.com/wincent/wincent.git

Arch Linux

sudo pacman -Syu
sudo pacman -S git ruby tmux vim
git clone --recursive https://github.com/wincent/wincent.git
  • git: In order to clone the repo.
  • ruby: So that git-cipher can run (also used to build Command-T).
  • tmux: Just for comfort (eg. so you can see scrollback).
  • vim: Because the nvim aspect needs Vim (it runs vim to do a :helptags update).

Install

โš ๏ธ WARNING: There are lots of different things that can be installed or configured (see the aspects/ directory). Unless you want your machine to be exactly like mine โ€” which is unlikely โ€” you probably don't want to install everything. Maybe you don't even want everything in the "dotfiles" and "nvim" aspects. Please inspect the contents of each aspect before proceeding to install it; you may even be better off just looking at the configuration files and stealing the bits that you find interesting or useful (everything is in the public domain, unless otherwise indicated).

At the time of writing, these are the aspects, which you can expect to change over time (see the aspects/ directory for an up-to-date listing):

  • On macOS only:
    • automator: Scripts for use with Automator
    • automount: Sets up macOS's automount facility
    • backup: Backup scripts
    • cron: Sets up cron files
    • defaults: Sets up defaults (ie. preferences) on macOS
    • fonts: Installs Source Code Pro font files
    • homebrew: Installs and updates Homebrew
    • iterm: Dynamic profiles for iTerm
    • karabiner: Configures Karabiner-Elements (keyboard customization).
    • launchd: Configures launchd
    • nix: Installs packages via the Nix package manager.
    • node: Installs Node.js
    • ruby: Installs Ruby gems
    • ssh: Manages local SSH config
    • tampermonkey: Sets up UserScripts
  • On Linux only:
    • apt: Installs packages using apt-get.
    • aur: Installs packages from the Arch User Repository.
    • avahi: Manages the Avahi zeroconf ("Bonjour") networking daemon.
    • codespaces: Custom tweaks for GitHub Codespaces environments.
    • interception: Sets up Interceptions Tools (keyboard customization).
    • locale: Sets up /etc/locale.conf
    • pacman: Installs packages via the Pacman package manager
    • sshd: Manages sshd.
    • systemd: Set up services that run from systemd
  • On both macOS and Linux:
    • dotfiles: Creates symlinks in $HOME to the dotfiles in this repo
    • meta: Tests the configuration framework
    • shell: Sets the use shell to zsh
    • terminfo: Sets up terminfo database entries for italics and 256-color support
    • nvim: Configures Neovim and Vim

Examples

./install dotfiles nvim     # Just install "dotfiles" and "nvim" stuff.
./install dotfiles          # Just install "dotfiles".
./install dotfiles --step   # Prompt for confirmation at each step.
./install dotfiles --check  # Do a dry-run, showing what would be changed.
./install                   # Install everything.
./install ^homebrew         # Install everything except for the "homebrew" aspect.
./install --help            # Lists all aspects, descriptions, options.

This sets up a local Node environment using n, and then uses Fig to copy the dotfiles and configure the machine.

Note: Given that ~/.config/git/config is included with these dotfiles, any local modifications or overrides that you apply should be added to ~/.config/git/config.local instead; for example:

git config --file ~/.config/git/config.local user.name "John Doe"
git config --file ~/.config/git/config.local user.email [email protected]

Manual steps

As much as I would love this thing to be entirely automated, there are some manual steps that must typically be performed.

macOS
  • In iTerm, mark the "Wincent" dynamic profile as the default: Preferences โ†’ Profiles โ†’ Other actions... โ†’ Set as Default
  • Set up full-disk access for iTerm: As described here, System Preferences โ†’ Security & Privacy โ†’ Privacy โ†’ Full Disk Access (and make sure that iTerm.app is in the list with the checkbox checked).

Troubleshooting

General troubleshooting

There are a few useful ./install options:

# Run in "check" (dry-run) mode.
./install --check

# Show debugging information during the run.
./install --debug

# Confirm each task before running it (--step), and begin
# execution from a specific task (--start-at-task) in a
# specific aspect ("dotfiles").
./install --step --start='make directories' dotfiles

./install hangs on the first run

If running on a brand new OS install where you have never used sudo before, ./install may appear to hang after requesting your password. This is because sudo may show a "lecture"3 on first run that requires you to respond to a prompt. When running in the context of ./install, you never see this prompt, because sudo is running in a subprocess, which causes the run to hang.

To avoid this, one time only, run sudo -v before running ./install.

License

Unless otherwise noted, the contents of this repo are in the public domain. See the LICENSE for details.

Authors

The repo is written and maintained by Greg Hurrell <[email protected]>. Other contributors that have submitted patches include, in alphabetical order:

  • Anton Kastritskiy
  • Hashem A. Damrah
  • Joe Lencioni
  • Jonathan Wilkins
  • Keng Kiat Lim
  • Mark Stenglein
  • Matthew Byrne
  • Michael Lohmann
  • Stone C. Lasley
  • Victor Igor
  • Zac Collier

This list produced with:

:read !git shortlog -s HEAD | grep -v 'Greg Hurrell' | cut -f 2-3 | sed -e 's/^/- /'

Security

As of commit ec49be762ff3 ("feat(dotfiles): automatically sign commits on personal machines", 2022-06-19) and commit 97143b5d7635 ("feat(dotfiles): sign commits everywhere except codespaces", 2022-06-20), I started signing most commits in this and other repos with GPG keys corresponding to my work and personal email addresses.

GitHub will label such commits with a "Verified" badge. In order to see signature information using the git commandline executable, you would run commands such as git show --show-signature and git log --show-signature. Note that in order to be able to actually verify these signatures you need a copy of the corresponding public keys, otherwise Git will show:

gpg: Signature made Mon 11 Jul 2022 11:50:35 CEST
gpg:                using RSA key B0C9C204D656540BDCDA86229F6B84B5B1E9955E
gpg:                issuer "[email protected]"
gpg: Can't check signature: No public key

You can obtain the public keys with the following:

# Either, download directly given the key fingerprint as shown by Git:
gpg --keyserver pgp.mit.edu --recv-key C7C225A18975180C4485A1E070516DBB88E4F779
gpg --keyserver pgp.mit.edu --recv-key B0C9C204D656540BDCDA86229F6B84B5B1E9955E

# Or, chose from a list of possible matches returned by searching for an email address:
gpg --keyserver https://pgp.mit.edu/ --search-keys [email protected]
gpg --keyserver https://pgp.mit.edu/ --search-keys [email protected]

You can also grab the keys from GitHub, if you trust GitHub:

curl https://github.com/wincent.gpg | gpg --import

Once you have those, Git will instead show:

gpg: Signature made Mon 11 Jul 2022 12:28:32 CEST
gpg:                using RSA key B0C9C204D656540BDCDA86229F6B84B5B1E9955E
gpg:                issuer "[email protected]"
gpg: Good signature from "Greg Hurrell <[email protected]>" [unknown]
gpg: WARNING: This key is not certified with a trusted signature!
gpg:          There is no indication that the signature belongs to the owner.
Primary key fingerprint: 2F44 69E0 C1FA 72AA C0A5  60C9 6210 6B56 923F 3481
     Subkey fingerprint: B0C9 C204 D656 540B DCDA  8622 9F6B 84B5 B1E9 955E

What's going on here, cryptographically speaking?

  • GPG keys consist of public and private parts, often referred to as public keys and private keys (together, a "key pair"). As the names suggest, the owner of the key must keep the private part secret, but the public part can be freely shared.
  • Roughly speaking, "signing" something means using the private key to encrypt a hash of the contents of the document that is being signed (in this case, the "document" is a commit).
  • The public key can be used to decrypt the hash, which can then be compared against the contents to confirm that they match. This is what is happening when we see gpg: Good signature above; it means that the public key for Greg Hurrell <[email protected]> verifies that the signature was indeed created with the corresponding private key belonging to that address.
  • Because only the owner has access to the private key, only the owner can make signatures with it; but conversely, because everybody has access to the public key, anybody can verify those signatures.
  • GPG keys have two additional concepts: "subkeys" are keys associated with a primary key; and "usages" describe what role those keys each play (eg. "signing", "encryption").
  • In practice, the primary key is always a "signing" key, and GPG will create one "encryption" subkey by default. Users can add/remove additional subkeys and assign them usages.
  • I create "signing" subkeys for making signatures and I rotate them once per year (I keep my primary key "offline" so that it can't be hacked if my machine is compromised).

So those are the cryptographic primitives. The signature is "Good" in the cryptographic sense, but why the scary "WARNING"? It's because there's a whole other layer on top of this called the "web of trust". A good signature gives us the mathematical certainty that a particular private key was used to produce a given signature, but that tells us nothing about the human world that exists above and around that crypto. That is, the key was used to make the signature, but was it me who used the key? Am I really the handsome Australian man living in Madrid claiming to be Greg Hurrell, or am I in fact part of a clandestine criminal organization operating from a satellite-connected submarine in the Arctic sea?

The web of trust serves to link your human-level trust relationships to the underlying digital entities. By running gpg --edit-key $KEY and hitting trust, you can explicitly record your level of trust in any given key, and you can do things like going to "key signing parties" and such where you can physically meet people, verify their identity by whatever means you deem appropriate, and then sign one another's public keys. The accrued effect of these actions over time is to establish a web of connections where trust is transitively applied: if you trust A and A trusts B, then you in turn can also trust B. Having said all that, how to actually go about building a useful web of trust is beyond the scope of this README, and in all my long years on the internet, I've never once gone to a key signing event or otherwise engaged in activity that would help me integrate my keys into a useful web of trust.

Footnotes

  1. The evenings were spent with vi derivatives, not with Bill Joy. โ†ฉ

  2. This isn't needed on Linux because we can achieve the same via a Kitty configuration. โ†ฉ

  3. See man sudoers. โ†ฉ

corpus's People

Contributors

codybuell avatar lencioni avatar wincent avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar

corpus's Issues

Fix egregious file-renaming bug

Not sure of the exact repro yet, but I've seen file renames turn out poorly, doing things like writing the content of the wrong file to be written to a given file.

Use dead code elimination in production build

I was originally looking at Babel's minification.deadCodeElimination option, but what I actually want is something that strips __DEV__ blocks out of stuff under node_modules like React as well.

Deal better with notes with slashes in the title

These currently "work", but not well:

  1. Create a new note with a slash in the title; see it as "foo/bar" in the UI, but "foo-bar" gets written to disk.
  2. Next time you open the app, you see "foo-bar" as the title.

Refactor OmniBar to address multiple typeahead issues

One example, with selected text indicated using [/]:

  • Type "test " (autocompletes "Test for [shellshock vulnerability]"
  • Add "n" (ie. trying to type "test note")
  • Becomes "[Test n]" (ie. everything selected); this is the bug
  • Add "o" (replaces everything)
  • Becomes "O[pen source projects]"

Another bug, this one for parity with nvALT:

  • Type "test " like above
  • It should autocomplete to "test [for shellshock vulnerability]" (note the case), even though the original note is "Test for shellshock Vulnerability"
  • Instead, it completes to "Test [for shellshock vulnerability]"

I feel like the whole OmniBar logic needs to be rewritten to better model that we effectively we have three pieces of state:

  1. What is the entered note title/file?
  2. What is the underlying represented title/file (if any)
  3. What is the text selection?

At the moment we're conflating (1) and (2) in an implicit way: (1) is stored in input.value and (2) is in this.state.value, and they interact with one another in confusing ways. (3) is stored in the DOM in a write-only way (we never read it, we just write to it).

I think I should try to pull these three pieces of state out somewhere explicit and then centralize the logic for accessing them and modifying them to make it really obvious what is going on.

Make "hidden" or "archived" notes

This idea just occurred to me, so not sure if it is great. I have nearly 1,000 notes and many of them aren't super relevant. I mostly want to exclude these from my working set and not have them clutter things up, but I don't necessarily want to delete them. Example: a project-related doc; once the project is over, I want to archive it, but may want to consult it in the future for some reason if I want to start up a similar project.

I am not sure what the best UX is for this. It could be as simple as adding a "hidden" or "archived" tag. Notes with this tag wouldn't show up in normal searches and views without an explicit #hidden search term. (Or something like that.)

Hashtag support

We plan to add label support, for parity with nvALT, but it would be cool to go a step further and have the ability to add labels just by including #hashtag text in your note text.

Possible gotcha: ambiguity with Markdown syntax at the start of lines. May be worth doing anyway.

Idea via @fkling.

Implement undo support for Note.react

We have native undo within Note.react as long as it is focused, but as soon as you switch to another note, the undo history is lost (we still have the Git history though).

Clicking on a tag should show notes with that tag

If I click on a tag "foo" in the note list, the search should become "#foo" and I should see notes with that tag.

(Relatedly note that "#foo" typed into the omni-bar should filter by tag instead of text).

Switch to Redux or Undux

And possibly, redux-saga and reselect. I'm hoping that this will provide me with the opportunity to tame some of the complexity that has emerged in terms of the interrelation between the various stores.

Alternatively, if not Redux, Undux.

Handle absence of ~/.corpusrc at startup more gracefully

Just switched to a new computer and noticed that we don't assume a reasonable default location (like ~/Documents/Corpus) for notes in the absence of a ~/.corpusrc.

I thought we did this but it looks like we don't. We should. This is more of a bug than an enhancement.

Rich-text mode

Edit Markdown source using a WYSIWYG style rich-text editor (not a separate preview).

Fix race between Command-K and modifying a note

Repro

  1. Start editing the second note in the note list
  2. Hit Command-K to move up to the first note

Expected behavior

  • (Visible) First note in list is selected
  • (Invisible) Changes to second note are persisted

Actual behavior

  • (Invisible) Changes to second note are persisted
  • (Visible) Changes cause second note to be bumped up to first place
  • (Visible) First note in list is selected, but it's now the note you just edited and probably not the one you want

For comparison, this is what nvALT does:

  • (Visible) Selection moves to first note
  • (Invisible) Presumably, changes get persisted to disk
  • (Visible) After a delay of about 1000ms, you see the edited note bubble to the top, and the previously first-note moves down one slot, but remains selected

The async nature of this can be a bit disconcerting, depending on whether you are trying to interact at the time (ie. with Command-{J,K}).

I'm not sure if either the Corpus or the nvALT behavior is ideal here.

Allow Corpus to read from multiple notes directories

Use case:

  • ~/Documents/Corpus/Personal/
  • ~/Documents/Corpus/Work/

All of ~/Documents/Corpus/ can be version controlled, but only Personal can get synced to Dropbox.

The gotcha: need to make it easy to add new notes to the right directory, and to change your mind easily if you do it wrong, and that means coming up with some UI for it.

OmniBar not selected on startup

nvALT will select all the text if a note was selected last time the app was open. If there was no note open, nothing is selected.

In corpus, we don't have that kind of selection persistence yet, so we just select the first note. You can see the text in the OmniBar getting selected, but it gets immediately deselected (even though the OmniBar retains focus).

Saved searches

There are a lot of ways this could be exposed in the UI, but not sure which one is best at this point. So leaving this issue as a placeholder.

Idea via @fkling.

Work around Jest crashes on Store-test.js

Importing ReactUpdates.batchedUpdates in our dispatcher implementation causes Jest to SIGSEGV. Commenting out that line "fixes" it.

I tried a few variations for mocking and not-mocking without success.

Make an asar build

May make require-ing faster, and obviate the need to do a rollup-based bundle.

Improve `warn` output when `open -R` fails

As noted in 1c01c1f the output here on failure isn't very helpful (just "1"). That's just the exit code of the process. We're not capturing standard error in run.js. Perhaps we should capture standard error as well as the exit code and pass them both back when rejecting the promise.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.