Open the door to every outhouse in the village in a single playthrough.
-
๐ Programming
General plugins I use in Neovim
I define a “general plugin” as a plugin that I use regardless of the filetype I’m editing.
These will add extra functionality for enhancing my Neovim experience.
I use Which-key for displaying keybindings as I type them. For example if I press my
<leader>
key and wait a few milliseconds, it will display all keybindings I have set that begin with my<leader>
key.It will also display any marks and registers I have set, when only pressing
'
or@
respectively.use "folke/which-key.nvim"
Vim-commentary makes it super easy to comment out lines in files using vim motions. So in normal mode you can enter
gcc
to comment out the current line; or5gcc
to comment out the next 5 lines.You can also make a visual selection and enter
gc
to comment out that selected block.use "tpope/vim-commentary"
Vim-surround provides me with an extra set of abilities on text objects. It lets me add, remove and change surrounding elements.
For example I can place my cursor over a word and enter
ysiw"
to surround that word with double quotes.Or I can make a visual selection and press
S"
to surround that selection with double quotes.use "tpope/vim-surround"
Vim-unimpaired adds a bunch of extra mappings that
tpope
had in his own vimrc, which he extracted to a plugin.They include mappings for the
[
and]
keys for previous and next items. For example using[b
and]b
moves backwards and forwards through your open buffers. Whilst[q
and]q
will move you backwards and forwards respectively through your quickfist list items.use "tpope/vim-unimpaired"
-
๐ Programming
Passive plugins I use in Neovim
These plugins I use in Neovim are ones I consider “passive”. That is, they just sit there doing their thing in the background to enhance my development experience.
Generally they wont offer extra keybindings or commands I will use day to day.
You can view all the plugins I use in my plugins.lua file in my dotfiles.
Vim-lastplace will remember the last edit position of each file you’re working with and place your cursor there when re-entering.
use "farmergreg/vim-lastplace"
Nvim-autopairs will automatically add closing characters when opening a “pair”, such as
{
,[
and(
. It will then place your cursor between the two.use "windwp/nvim-autopairs"
Neoscroll makes scrolling smooth in neovim.
use "karb94/neoscroll.nvim"
Vim-pasta will super-charge your pasting in neovim to preserve indents when pasting contents in with “
p
” and “P
“.use({ "sickill/vim-pasta", config = function() vim.g.pasta_disabled_filetypes = { 'fugitive' } end, })
Here I am passing a config function to disable vim-pasta for “fugitive” filetypes. “Fugitive” is in reference to the vim-fugitive plugin that I will explain in another post.
Nvim-colorizer will highlight any colour codes your write out.
use "norcalli/nvim-colorizer.lua"
-
๐ Programming
How I use Neovim
I try to use Neovim for as much development-related work as possible.
This page serves as a point of reference for me, and other people interested, for what I use and how I use it.
Feedback is welcome and would love to know how you use Neovim too!
My complete Neovim configuration files can be found on Github.
- How I organise my Neovim configuration
- Passive plugins I use in Neovim
- General plugins I use in Neovim
- Development plugins I use in Neovim – coming soon
- Database client in Neovim (vim-dadbod and vim-dadbod-ui) – coming soon
- REST client in Neovim (vim-rest-client) – coming soon
- Personal Wiki in Neovim (vim-wiki) – coming soon
-
๐ Journal
Technical Difficulties by Racer X
One of my favourite Paul Gilbert songs from his time in Racer X.
Absolutely incredible riffs throughout.
-
Lights Out – The Last of Us Part I
While in stealth, turn off the spotlight generator in Pittsburgh.
-
๐ Journal
I read old books
I read old books because I would rather learn from those who built civilization than those who tore it down.
-
10 Types of Machine Overridden – Horizon Forbidden West
Unlocked and used the overrides for 10 different types of machine.
-
๐ Journal
Got the Chas and Dave itch again. Love these guys and the music just instantly makes me happy.
-
๐ Journal
Incredible shot from The Last of Us episode 6
Another incredible episode of The Last of Us.
The references were so great too. Shimmer; Dina in the background; farm with sheep.
Next week will be the episode with David and it’s gonna be so very dark and have one of the best episode endings so far I reckon.
-
๐ Programming
Inventory app — saving inventory items.
This is the absolute bare bones minimum implementation for my inventory keeping: saving items to my inventory list.
Super simple, but meant only as an example of how I’d work when working on an API.
Here are the changes made to my Inventory Manager. Those changes include the test and logic for the initial index endpoint too. I may blog about that part in a separate post soon.
Writing the store test
One of Laravel’s many strengths is how well it is set up for testing and just how nice those tests can read. Especially now that I’ve started using Pest.
Here is the test I wrote for the
store
endpoint I was yet to write:test('inventory items can be created', function () { $response = $this->postJson(route(name: 'inventory.store'), [ 'name' => 'My Special Item', ]); $response->assertStatus(201); $this->assertDatabaseHas(Inventory::class, [ 'name' => 'My Special Item', ]); });
Firstly I post to an endpoint, that I am yet to create, with the most minimal payload I want: an item’s name:
$response = $this->postJson(route(name: 'inventory.store'), [ 'name' => 'My Special Item', ]);
Then I can check I have the correct status code: an HTTP Created 201 status:
$response->assertStatus(201);
Finally I check that the database table where I will be saving my inventory items has the item I have created in the test:
$this->assertDatabaseHas(Inventory::class, [ 'name' => 'My Special Item', ]);
The first argument to the
assertDatabaseHas
method is the model class, which Laravel will use to determine the name of the table for that model. Either by convention, or by the value you override it with on the model.The second argument is an array that should match the table’s column name and value. Your model can have other columns and still pass. It will only validate that the keys and values you pass to it are correct; you don’t need to pass every column and value — that would become tedious.
Writing the store logic
There is a term I’ve heard in Test-driven development called “sliming it out”. If I remember correctly, this is when you let the test feedback errors dictate every single piece of code you add.
You wouldn’t add any code at all until a test basically told you too.
I wont lie – I actually love this idea, but it soon becomes tiresome. It’s great to do when you start out in TDD, in my opinion, but soon you’ll start seeing things you can add before running the test.
For example, you know you’ll need a database table and a model class, and most likely a Model Factory for upcoming tests, so you could run the artisan command to generate those straight away:
php artisan make:model -mf Inventory # or with sail ./vendor/bin/sail artisan make:model -mf Inventory
I dont tend to generate my Controller classes with these, as I now use single-action controllers for personal projects.
Store Route
Within the
routes/web.php
file, I add the following:use App\Http\Controllers\Inventory\StoreController; Route::post('inventory', StoreController::class)->name('inventory.store');
Using a single-action class here to keep logic separated. Some would see this as over-engineering, especially if keeping controller code to a minimum anyway, but I like the separation.
Adding an explicit “name” to the endpoint, means I can just refer to it throughout the app with that name. Like in the test code above where I generate the endpoint with the “route” helper function:
route(name: 'inventory.store')
Store Controller
<?php declare(strict_types = 1); namespace App\Http\Controllers\Inventory; use App\Http\Requests\InventoryStoreRequest; use App\Models\Inventory; use Illuminate\Contracts\Routing\ResponseFactory; use Illuminate\Http\Response; class StoreController { public function __invoke(InventoryStoreRequest $request): Response|ResponseFactory { Inventory::create([ 'name' => $request->get(key: 'name'), ]); return response(content: 'Inventory item created', status: 201); } }
Super straight forward at the moment. After receiving the request via the custom request class (code below), I just create an inventory item with the name on the request.
I then return a response with a message and an HTTP Created 201 status.
This code does assume that it was created fine so I might look at a better implementation of this down the line…
…but not before I have a test telling me it needs to change.
InventoryStoreRequest class
This is a standard generated request class with the following
rules
method:/** * Get the validation rules that apply to the request. * * @return array<string, mixed> */ public function rules(): array { return [ 'name' => 'required', ]; }
Again, nothing much to it. It makes sure that a name is required to be passed.
Its not saying anything about what that value could be. We could pass a date time or a mentally-long string.
I’ll fix that in a future post.
An extra test for the required name
In order to be “belt and braces”, I have also added a test that proves that we require a name to be passed. Pest makes this laughable simple:
test('inventory items require a name', function () { $this->postJson(route(name: 'inventory.store')) ->assertJsonValidationErrorFor('name'); });
This just performs a post request to the store endpoint, but passes no data. We then just chain the
assertJsonValidationErrorFor
method, giving it the parameter that should have caused the failed validation. In this case “name”.As the validation becomes more sophisticated I will look at adding more of these tests, and even possibly running all “required” fields through the some test method with Pests data functionality. Essentially the same as how PHPUnit’s Data Providers work.
Useful Links
Complete changes in git for when I added the store and the index endpoints to my Inventory app.
๐ท๏ธ PHP
-
๐ Programming
Connecting to a VPN in Arch Linux with nmcli
nmcli
is the command line tool for interacting with NetworkManager.For work I sometimes need to connect to a vpn using an
.ovpn
(openvpn) file.This method should work for other vpn types (I’ve only used
openvpn
)Installing the tools
All three of the required programs are available via the official Arch repositories.
networkmanager
(with contains the nmcli tool). You’ve probably already got this installed if you’re reading this.- openvpn
- networkmanager-openvpn (to allow networkmanager to manage OpenVPN connections)
Importing the
ovpn
file into your Network ManagerOnce you’ve got the openvpn file on your computer, you can import it into your Network Manager configuration with the following command:
# Replace the file path with your own correct one. nmcli connection import type openvpn file /path/to/your-file.ovpn
You should see a message saying that the connection was succesfully added.
Activate the connection
Activating the connection will connect you to the VPN specified with that
.ovpn
file.nmcli connection up your-file
If you need to provide a password to your vpn connection, you can add the
--ask
flag, which will make theconnection up
command ask you for a password:nmcli connection up your-file --ask
Disconnect
To disconnect from the VPN, just run the
down
command as follows:nmcli connection down you-file
Other Links:
-
-
Completed a Set of Salvage Contracts – Horizon Forbidden West
Completed all contracts at a Salvage Contractor.