[{"content":" This guide is specifically pertaining to the concept of using public and private keys to securely transfer data. Concepts like signing and key verification will be covered in another post.\nAsymmetrical encryption (also known as public and private key encryption) is a simple idea that often gets explained with the worst possible analogies.\nEven the word \u0026ldquo;keys\u0026rdquo; can trip us up. We normally think of one key opening one lock, but GPG keys don\u0026rsquo;t work like that at all.\nThis post is my attempt to give a clearer illustration of how public and private keys work, and why we use them.\nImportant terminology Encrypting: scrambling a file so its contents can\u0026rsquo;t be understood without the right key. Decrypting: unscrambling the file so the original contents can be read. My illustration Think of each public/private key pair as a magic marker and a magic eraser.\nThe marker is like the public key: anyone can use it. The eraser is like the private key: only the owner should have it. They\u0026rsquo;re magically bound together, and anything written with the marker can only be erased with its matching eraser.\nHere\u0026rsquo;s how it plays out:\nYou write a letter with a pencil. You borrow your friend\u0026rsquo;s magic marker (their public key) and scribble over your letter. Now it looks like a messy blob no one can read. You pass the letter to your friend. They use their magic eraser (their private key) to remove the scribbles, revealing the pencil text underneath. Why do we even need this? Let\u0026rsquo;s say you want to send George this letter:\nG W S e e e o ' e r r g e y e o , m u e e t t h i e n n g a t m i d n i g h t a t t h e L o s t I n n . You need to send it over the internet, but you don\u0026rsquo;t want anyone else snooping. So you ask George for his \u0026ldquo;magic marker\u0026rdquo;, his public key.\nWhen you encrypt your letter with George\u0026rsquo;s public key, it\u0026rsquo;s like covering it in ink only he can remove. Even if someone intercepts it, all they\u0026rsquo;ll see is scrambled nonsense.\nBut what\u0026rsquo;s actually happening? Rather than a magic marker writing over a letter, encryption is transforming the data behind a file in a predictable, mathematically driven way.\nThe same key, given the same input file, will always produce the same output file.\nIt\u0026rsquo;s worth noting GPG also adds a bit of random \u0026ldquo;session data\u0026rdquo;, thus the same file encrypted for the same person will vary a bit.\nThe math gets really complicated when you consider how we can use a private key to decrypt a file encrypted by a public key, so we\u0026rsquo;ll shelf the math and really try to understand what\u0026rsquo;s happening:\nA public key can be used to encrypt a file into random data, and the original contents can only be restored by its corresponding private key. The public key cannot be used to decrypt the data back to its original form, it\u0026rsquo;s a one way street. The math is clever, a private key cannot be derived from the public key. This way you can post your public key on your blog, site, etc., allowing people to securely send you files. Although not covered in this post, private keys can also be used to \u0026ldquo;sign\u0026rdquo; files. Public keys can be used to validate the authenticity of these signatures.\nWhen would I ever use this? Most private messaging apps are using a similar method, but at a more advanced and under-the-hood level.\nThat being said, there are still valid reasons to use GPG encryption when transferring files, even when using a generally secure platform.\nUploading sensitive information to public servers Say you want to disperse a file of sensitive information to your community on Discord. Discord files are stored on a public server, meaning files uploaded to it are always publicly available. All you need to access the file is the related link.\nBut if you ask your community members to provide you with their public keys, you could create one-off encrypted versions, unique to each user.\nWhistleblowers and journalists Edward Snowden famously used a GPG email client to securely communicate with journalists, eventually uncovering a vast surveillance network employed by the US government.\nGenerating your own key pair Generating your own keypair is as simple as running the following command:\n$ gpg --full-generate-key You will be asked to provide a name, an email, and a passphrase. It is important you provide an accurate email address, as it is used by others when encrypting a file with your public key.\nYou can also optionally set an expiration date for the key, which can later be extended.\nYour new key is stored in your local \u0026ldquo;keychain\u0026rdquo;. You can see what keys you have stored with the following:\n$ gpg --list-keys [keyboxd] --------- pub ed25519 2025-08-29 [SC] 2FE85E547FA7E26536DF733B445719E43214E8E8 uid [ultimate] Joshua Lee \u0026lt;joshpaullee@gmail.com\u0026gt; sub cv25519 2025-08-29 [E] You can then export your public key to a text file (the .asc extension indicates it\u0026rsquo;s in ASCII-armored format, making it human-readable text rather than binary):\n$ gpg --export --armor your_email@example.com \u0026gt; public_key.asc Using someone\u0026rsquo;s public key to encrypt a file Now that you have your key setup, let\u0026rsquo;s see how we can import someone else\u0026rsquo;s public key to encrypt secret-note.txt.\nFor this example, I\u0026rsquo;ll use a public key generated for \u0026ldquo;George Freeman\u0026rdquo;, using the email george@free.io. We\u0026rsquo;ll pretend I copied the key off of his blog, and is saved to a text file named george.asc.\nFirst, this public key needs to be imported into my keyring:\n$ gpg --import george.asc gpg: key D04B6D7873E18E48: public key \u0026#34;George Freeman \u0026lt;george@free.io\u0026gt;\u0026#34; imported gpg: Total number processed: 1 gpg: imported: 1 ⚠️ Security Note: This is a simple introduction, but it\u0026rsquo;s paramount you understand the importance of verifying the authenticity of any public key before you import it. What if poor George had his blog compromised, and a third party replaced his key with theirs?\nVerification (e.g., via fingerprints) will be covered in a future post.\nWe can list the keys again to verify it\u0026rsquo;s been added to my keyring:\n$ gpg --list-keys [keyboxd] --------- pub ed25519 2025-08-29 [SC] 2FE85E547FA7E26536DF733B445719E43214E8E8 uid [ultimate] Joshua Lee \u0026lt;joshpaullee@gmail.com\u0026gt; sub cv25519 2025-08-29 [E] pub ed25519 2025-08-29 [SC] [expires: 2028-08-28] 5BECEF3C026112BAB597B5E0D04B6D7873E18E48 uid [ unknown] George Freeman \u0026lt;george@free.io\u0026gt; sub cv25519 2025-08-29 [E] [expires: 2028-08-28] Now I can encrypt my secret note with George\u0026rsquo;s public key:\n$ gpg --encrypt --recipient \u0026#34;george@free.io\u0026#34; secret-note.txt Which produces a new file: secret-note.txt.gpg. I can now confidently send my note to George, knowing only he can decrypt the file with his private key.\nConclusion And that\u0026rsquo;s that! While many modern apps handle this encryption for you automatically, understanding GPG gives you direct control for situations where those apps aren\u0026rsquo;t an option.\nThis isn\u0026rsquo;t the full picture, and the power of GPG really comes into play when we start signing files. But these fundamentals are important to understand when diving into other encryption topics.\n","permalink":"https://bexli.dev/posts/compsci/gpg/gpg-keys-intro/","summary":"A simple way to understand what GPG keys are and why we use them.","title":"Making Sense of GPG Keys"},{"content":"Intro I recently inherited my brother\u0026rsquo;s old desktop. It\u0026rsquo;s a modest upgrade from my 2017 budget build, but with a notable behavior: it frequently crashed under load. Without performance issues or error messages, it completely powers off as if the power cable was abruptly ripped out.\nMy brother explained this began after upgrading his graphic card to an RTX. He (logically) believed this to be a power supply issue, considering all of the involved hardware was compatible. So he ordered and installed a new power supply, only for the issue to persist. He eventually couldn\u0026rsquo;t live with the constant crashes, and ordered himself a new rig. The old system was then relegated to the garage.\nMaybe a year later, I abducted the setup to see if I could resolve the issue.\nMy first solution was flash it with a new Windows install and cosmically will the issues to resolve themselves. It worked for a deceiving amount of time but finally did crash while gaming. My next solution was to chalk that crash up as a fluke and ignore it. That wasn\u0026rsquo;t much help either.\nAfter doing the basics (like ensuring all drivers were up to date, reseating the cables), my actual next step was checking out the Event Viewer, which had the following helpful entries:\nP e r f o r m a n c e p o w e r m a n a g e m e n t f e a t u r e s o n p r o c e s s o r 1 i n g r o u p 0 a r e d i s a b l e d d u e t o a f i r m w a r e p r o b l e m . C h e c k w i t h t h e c o m p u t e r m a n u f a c t u r e r f o r u p d a t e d f i r m w a r e . This indicates 2 issues to me: a motherboard issue, or a power issue. We had already replaced the power supply, so it must be a motherboard issue.\nUpdating the motherboard firmware Frankly, I\u0026rsquo;m not sure how one goes about troubleshooting a motherboard issue, so I went the easiest route first: update the BIOS firmware. Used winfetch to grab the motherboard model and found it was an Asus PRIME B350-PLUS. Quick google search led me to the BIOS firmware download link.\nUnder the \u0026ldquo;Driver and tools\u0026rdquo; section, we\u0026rsquo;re informed this must be manually updated:\nWe don\u0026rsquo;t currently provide a software utility or drivers for this model.\nBeneath the BIOS section was a single entry for my board: version 6232, released in 2024.\nI booted into the BIOS to see what version we were currently rocking: version 803, released in 2017.\nConsidering the RTX card was released in 2019, I figured it was safe to assume my fix was somewhere in the 5,429 patches released since.\nAfter hitting the download button for the sole entry, I was provided a zip archive with 2 files:\nBIOSRenamer.exe PRIME-B350-PLUS-ASUS-6232.CAP With no other instructions provided, I sensibly ran the mystery .exe and hoped for the best.\nIt seems the executable determined the exact model of motherboard I was using, and renamed that .CAP file to some sort of logical identifier. In my case, PRIME-B350-PLUS-ASUS-6232.CAP was renamed to PRB350PS.CAP\nNow what? Read the manual I guess. 🤮\nSection 2.1.2 of the board\u0026rsquo;s manual states I need to save this .CAP file to a USB, but specifically one formated with FAT32/FAT16. Windows didn\u0026rsquo;t offer either in the builtin formatting tool, likely because format was made for much smaller USBs, and was only offering exFAT.\nDownloaded ol\u0026rsquo; reliable, Rufus, and got the thumb drive formatted properly. Moved the .CAP file onto the stick, and booted back into the BIOS.\nFrom the BIOS went to Advanced Mode \u0026gt; Tool \u0026gt; ASUS EZ Flash 3 Utility \u0026gt; \u0026ldquo;Via storage device\u0026rdquo;. My USB and file was already selected from the list of drives, I simply hit \u0026lt;Enter\u0026gt; and confirmed the change.\nResults After booting into my machine, I downloaded all of the GPU stress tests I could find. Ran quite a few tests, including benchmarks, and didn\u0026rsquo;t have any crashes. Been using and abusing the system with my racing games for a few weeks now, it now runs like a champ.\nWas pretty happy to give the garage PC a second life.\n","permalink":"https://bexli.dev/posts/troubleshooting/garage-pc/","summary":"The adventure of updating a Prime B350-PLUS BIOS.","title":"Resurrecting the garage PC"},{"content":"Over the past week, I wrote my first VSCode extension: VSNotify. It came out of \u0026ldquo;necessity\u0026rdquo;, as I wanted keybindings to display text in the status bar, similar to how echo works in Neovim. Here\u0026rsquo;s what I wanted to replicate:\nvim.keymap.set(\u0026#39;n\u0026#39;, \u0026#39;h\u0026#39;, \u0026#39;\u0026lt;cmd\u0026gt;echo \u0026#34;Use a better motion! (b, ge, F)\u0026#34;\u0026lt;CR\u0026gt;\u0026#39;) It\u0026rsquo;s a niche use case, but I was surprised that:\nThere\u0026rsquo;s no way to invoke vscode.window.showInformationMessage or vscode.window.setStatusBarMessage directly from keybindings. Nothing like this already existed. So, here we are.\nUltimately, I was able to emulate the same behavior as the Neovim example:\n{ \u0026#34;vim.normalModeKeyBindings\u0026#34;: [ { \u0026#34;before\u0026#34;: [\u0026#34;h\u0026#34;], \u0026#34;commands\u0026#34;: [ { \u0026#34;command\u0026#34;: \u0026#34;vsnotify.status\u0026#34;, \u0026#34;args\u0026#34;: { \u0026#34;message\u0026#34;: \u0026#34;Use a better motion! (b, ge, F)\u0026#34;, \u0026#34;color\u0026#34;: \u0026#34;red\u0026#34; } } ], \u0026#34;silent\u0026#34;: true } ] } Here are my thoughts on writing my first extension.\nThe Developer Experience Microsoft and the community have done an excellent job with the extension lifecycle. This is just a high-level overview, but their Getting Started guide is fantastic.\nStarting Off It all begins with Yeoman, a scaffolding tool for the JS/TS ecosystem. Paired with the generator-code package, you can generate a base extension with yo code. After answering a few questions in the wizard, it scaffolds out your starting point.\nFor this project, I used unbundled TypeScript and npm.\nWriting the Extension Actually writing the extension was pretty straightforward. VSNotify is essentially just passing user arguments into a status bar message or popup.\nCreating a Command Each command is a function, and I created a basic interface to type the user arguments, providing autocompletion later.\nCommands are defined in package.json, along with any relevant settings. Users can bind these commands to keyboard shortcuts, with either keybindings.json or VSCodeVim bindings, to create custom notifications.\nThe notify command is the simplest of the three and demonstrates this clearly.\nPackaging and Publishing Packaging and publishing are handled by vsce, another CLI tool. After creating a Visual Studio Marketplace publisher and authing with vsce, you can just run:\nvsce package \u0026amp;\u0026amp; vsce publish And that\u0026rsquo;s it. About five minutes later, anyone in the world can install your extension.\nAdditional Functionality I also added a task runner to VSNotify. You can bind a task as usual, but with VSNotify you get a custom notification on success or failure.\n// With VSNotify { \u0026#34;key\u0026#34;: \u0026#34;ctrl+h\u0026#34;, \u0026#34;command\u0026#34;: \u0026#34;vsnotify.runTask\u0026#34;, \u0026#34;args\u0026#34;: { \u0026#34;taskName\u0026#34;: \u0026#34;build\u0026#34;, \u0026#34;useStatus\u0026#34;: true // true = status bar, false = popup } } // Traditional way { \u0026#34;key\u0026#34;: \u0026#34;ctrl+h\u0026#34;, \u0026#34;command\u0026#34;: \u0026#34;workbench.action.tasks.runTask\u0026#34;, \u0026#34;args\u0026#34;: \u0026#34;build\u0026#34; } That\u0026rsquo;s all for this one. Here\u0026rsquo;s a demo of it in action. I\u0026rsquo;m curious if anyone else comes up with other use cases!\n","permalink":"https://bexli.dev/posts/vscode/vsnotify/","summary":"My first VSCode extension: VSNotify","title":"VSNotify"},{"content":"I\u0026rsquo;ve had to return to VSCode (from Neovim) for work. Here are some thoughts on how I\u0026rsquo;m getting the most Neovim-like experience possible.\nNote: I won\u0026rsquo;t be going into too much detail, as I expect the reader to also be transitioning from Neovim to VSCode.\nSidenote: Extensions aren\u0026rsquo;t so bad I do miss declaratively defining plugins, but having a little marketplace to install everything from LSPs to themes is nice.\nWhat\u0026rsquo;s not so nice? Having to define ALL of your extension settings in a single settings.json. Microsoft, please give us modular config files.\nVim-er VSCode { \u0026#34;editor.cursorSurroundingLines\u0026#34;: 10, // Scrolloff \u0026#34;editor.cursorBlinking\u0026#34;: \u0026#34;solid\u0026#34;, // Static cursor \u0026#34;editor.lineNumbers\u0026#34;: \u0026#34;relative\u0026#34;, // Rel line numbers \u0026#34;editor.semanticHighlighting.enabled\u0026#34;: true, // Treesitter-like highlighting \u0026#34;vim.useSystemClipboard\u0026#34;: true, // OPTIONAL \u0026#34;window.restoreWindows\u0026#34;: \u0026#34;none\u0026#34;, // Blank window \u0026#34;workbench.startupEditor\u0026#34;: \u0026#34;none\u0026#34;, // when opening } General VSCode clutter { \u0026#34;editor.minimap.enabled\u0026#34;: false, \u0026#34;editor.stickyScroll.enabled\u0026#34;: false, \u0026#34;workbench.sideBar.location\u0026#34;: \u0026#34;right\u0026#34; } VSCode Text Objects: The bread and butter If you\u0026rsquo;re a Neovim refugee as well, you know how indispensable text objects are.\nVSCode Textobjects is a phenomenal reimplementation of Treesitter\u0026rsquo;s Textobjects. It\u0026rsquo;s written by a solo dev and somehow only has 5 stars, with around 115 downloads.\nIt supports a TON of languages and is incredibly well thought-out. After copying/merging in the config snippet, all the standard Vim text object motions are available, but for actual programming objects (classes, functions, variable names/values, loops, conditionals). It\u0026rsquo;s as close to perfect as VSCode will allow.\nThe toughest part is that you must manually configure all text object motions in your config file. Not so bad, you\u0026rsquo;d have to do the same in Neovim. But this is hundreds of lines long, and we only have one config file to work with.\nAgain, Microsoft, PLEASE let us modularize our configs.\nAnother limitation is that you only get the \u0026ldquo;vanilla\u0026rdquo; editing operations (visual select, replace, delete, etc). While it covers most needs, there are some constraints:\nCan\u0026rsquo;t comment out the body of a function with gcif Solution: visually select the inner contents first, then comment with vifgc This occurs because both VS Text Objects and VSCodeVim are emulation layers. Unless they were merged, their motions remain unaware of each other.\nVSCodeVim VSCodeVim is more than just motion emulation. It includes many essential plugins built-in, some enabled by default. My favorites:\nvim-easymotion (Disabled) Quickly jump to any visible character:\n{ \u0026#34;vim.easymotion\u0026#34;: true, \u0026#34;vim.normalModeKeyBindingsNonRecursive\u0026#34;: [ { \u0026#34;before\u0026#34;: [\u0026#34;s\u0026#34;], \u0026#34;after\u0026#34;: [\u0026#34;\u0026lt;leader\u0026gt;\u0026#34;, \u0026#34;\u0026lt;leader\u0026gt;\u0026#34;, \u0026#34;s\u0026#34;] } ] } Your browser does not support the video tag. vim-surround (Enabled) Surround objects with characters (quotes, brackets, backticks, visual selection, etc). Great for turning symbol into a \u0026quot;string\u0026quot; (ysiw\u0026quot;), or changing a list [1, 2, 3] into a set {1, 2, 3} (cs]})\nYour browser does not support the video tag. Tips To surround your visual selection, use S. This differs from vim-surround in Neovim, where S is not used by default.\nYour browser does not support the video tag. When surrounding with brackets, use: Opening brackets ({, [, () to loosely wrap (leave a space) Closing brackets (}, ], )) to tightly wrap [ \u0026#34;This is loosely wrapped\u0026#34; ] [\u0026#34;This is tightly wrapped\u0026#34;] vim-commentary (Enabled) Comment text with gc:\nYour browser does not support the video tag. CamelCaseMotion (Disabled) Edit PascalCase, camelCase, and snake_case symbols:\nYour browser does not support the video tag. ReplaceWithRegister (Disabled) Overwrite text without losing clipboard content using gr\n(Based on the vim-substitute plugin)\nYour browser does not support the video tag. vim-textobj-entire (Enabled) Quickly perform edits/actions against the entire file.\nI love using yae (from vim-textobj-entire) to copy my whole file to my system clipboard, but don\u0026rsquo;t like how it snaps my cursor to the start of the file. My hack is to mark (and return to) my current location:\n{ \u0026#34;vim.normalModeKeyBindingsNonRecursive\u0026#34;: [ { \u0026#34;before\u0026#34;: [\u0026#34;y\u0026#34;, \u0026#34;a\u0026#34;, \u0026#34;e\u0026#34;], \u0026#34;after\u0026#34;: [\u0026#34;m\u0026#34;, \u0026#34;z\u0026#34;, \u0026#34;y\u0026#34;, \u0026#34;a\u0026#34;, \u0026#34;e\u0026#34;, \u0026#34;`\u0026#34;, \u0026#34;z\u0026#34;] } ] } VSCodeVim Settings Here are my recommended VSCodeVim settings, not including bindings.\nEnables all the above Vim plugins Sets space to leader \u0026ldquo;Highlight on yank\u0026rdquo; Clearer searching { \u0026#34;vim.easymotion\u0026#34;: true, \u0026#34;vim.hlsearch\u0026#34;: true, \u0026#34;vim.incsearch\u0026#34;: true, \u0026#34;vim.leader\u0026#34;: \u0026#34;\u0026lt;space\u0026gt;\u0026#34;, \u0026#34;vim.useSystemClipboard\u0026#34;: true, \u0026#34;vim.camelCaseMotion.enabled\u0026#34;: true, \u0026#34;vim.highlightedyank.duration\u0026#34;: 75, \u0026#34;vim.highlightedyank.enable\u0026#34;: true, \u0026#34;vim.sneak\u0026#34;: true, \u0026#34;vim.sneakUseIgnorecaseAndSmartcase\u0026#34;: true, \u0026#34;vim.replaceWithRegister\u0026#34;: true } Key Bindings Splits Management { \u0026#34;vim.normalModeKeyBindingsNonRecursive\u0026#34;: [ { \u0026#34;before\u0026#34;: [\u0026#34;leader\u0026#34;, \u0026#34;v\u0026#34;], \u0026#34;commands\u0026#34;: [\u0026#34;:vsplit\u0026#34;] }, { \u0026#34;before\u0026#34;: [\u0026#34;leader\u0026#34;, \u0026#34;s\u0026#34;], \u0026#34;commands\u0026#34;: [\u0026#34;:split\u0026#34;] }, { \u0026#34;before\u0026#34;: [\u0026#34;leader\u0026#34;, \u0026#34;h\u0026#34;], \u0026#34;commands\u0026#34;: [\u0026#34;workbench.action.focusLeftGroup\u0026#34;] }, { \u0026#34;before\u0026#34;: [\u0026#34;leader\u0026#34;, \u0026#34;k\u0026#34;], \u0026#34;commands\u0026#34;: [\u0026#34;workbench.action.focusAboveGroup\u0026#34;] }, { \u0026#34;before\u0026#34;: [\u0026#34;leader\u0026#34;, \u0026#34;j\u0026#34;], \u0026#34;commands\u0026#34;: [\u0026#34;workbench.action.focusBelowGroup\u0026#34;] }, { \u0026#34;before\u0026#34;: [\u0026#34;leader\u0026#34;, \u0026#34;l\u0026#34;], \u0026#34;commands\u0026#34;: [\u0026#34;workbench.action.focusRightGroup\u0026#34;] } ] } Indentation The following allows you to visually select lines and spam \u0026lt;/\u0026gt; to align them.\n{ \u0026#34;vim.visualModeKeyBindings\u0026#34;: [ { \u0026#34;before\u0026#34;: [\u0026#34;\u0026gt;\u0026#34;], \u0026#34;commands\u0026#34;: [\u0026#34;editor.action.indentLines\u0026#34;] }, { \u0026#34;before\u0026#34;: [\u0026#34;\u0026lt;\u0026#34;], \u0026#34;commands\u0026#34;: [\u0026#34;editor.action.outdentLines\u0026#34;] } ] } Go-to next problem Requires Go to Next Problem\nGo to the next warning or error.\nThe odd \u0026ldquo;toggle vim \u0026gt; action \u0026gt; toggle vim \u0026gt; vim_escape\u0026rdquo; is a workaround for a VSCode behavior.\n{ \u0026#34;vim.normalModeKeyBindingsNonRecursive\u0026#34;: [ // Goto next problem { \u0026#34;before\u0026#34;: [\u0026#34;leader\u0026#34;, \u0026#34;g\u0026#34;, \u0026#34;e\u0026#34;], \u0026#34;commands\u0026#34;: [\u0026#34;toggleVim\u0026#34;, \u0026#34;go-to-next-problem.nextInFiles\u0026#34;, \u0026#34;toggleVim\u0026#34;, \u0026#34;extension.vim_escape\u0026#34;], \u0026#34;silent\u0026#34;: true, \u0026#34;args\u0026#34;: { \u0026#34;severity\u0026#34;: [\u0026#34;error\u0026#34;, \u0026#34;warn\u0026#34;] }, \u0026#34;when\u0026#34;: \u0026#34;editorFocus\u0026#34; }, // Goto previous problem { \u0026#34;before\u0026#34;: [\u0026#34;leader\u0026#34;, \u0026#34;g\u0026#34;, \u0026#34;E\u0026#34;], \u0026#34;commands\u0026#34;: [\u0026#34;toggleVim\u0026#34;, \u0026#34;go-to-next-problem.prevInFiles\u0026#34;, \u0026#34;toggleVim\u0026#34;, \u0026#34;extension.vim_escape\u0026#34;], \u0026#34;silent\u0026#34;: true, \u0026#34;args\u0026#34;: { \u0026#34;severity\u0026#34;: [\u0026#34;error\u0026#34;, \u0026#34;warn\u0026#34;] }, \u0026#34;when\u0026#34;: \u0026#34;editorFocus\u0026#34; } ] } Error lens Inline error messages.\nRequires Error Lens\n{ // Personally, I remove the \u0026#34;info\u0026#34; disagnostic level, as I also use spell check plugins // Which I don\u0026#39;t need inline errors for. \u0026#34;errorLens.enabledDiagnosticLevels\u0026#34;: [\u0026#34;error\u0026#34;, \u0026#34;warning\u0026#34;], } Read More These are my thoughts so far. For deeper customization, check the VSCodeVim README.\nI\u0026rsquo;ll be doing additional write-ups for my whole settings.json and an in-depth (video?) on VSCode Text Objects.\n","permalink":"https://bexli.dev/posts/vscode/back-to-vscode/","summary":"Making VSCode Neovim-esque as I can","title":"Back to VSCode"},{"content":"This short guide shows how to configure Ruff and Pylance to work cleanly together in VSCode.\nIf you\u0026rsquo;ve recently added Ruff to your Python workflow, you may have noticed duplicate diagnostics in your editor. That\u0026rsquo;s because Pylance, by default, performs its own linting alongside Ruff.\nTo avoid duplicated linting and retain all the great language features of Pylance (like type inference, autocomplete, symbol renaming, and more), disable its linting with the following:\n{ \u0026#34;python.analysis.ignore\u0026#34;: [ \u0026#34;*\u0026#34; ] } What about MyPy? Ruff does not perform type checking (related Astral tool is in the works), so you should keep MyPy installed if you use static typing. There are no conflicts between MyPy and Ruff.\n","permalink":"https://bexli.dev/posts/vscode/ruff-pylance/","summary":"Configure Ruff and Pylance to work together in VSCode without redundant linting warnings.","title":"Ruff \u0026 Pylance for VSCode"},{"content":"Ruff is a Python linter and formatter written in Rust by the Astral team. This guide is to illustrate which extensions it replaces in VSCode, and some changes you\u0026rsquo;ll likely want to make.\nRelated: Ruff \u0026amp; Pylance\nConsolidating extensions Pretty much out-of-the-box, Ruff replaces Black, isort, and Pylint.\nRuff replicates formatting behavior from Black and isort, including import sorting, quote consistency, and line wrapping. You can use it as your default formatter. Ruff re-implements linting rules from popular tools like Flake8, perflint, and Pydocstyle. This allows you to consolidate nearly all Python linting into one tool. Configuring Ruff Note: There are many, many ways for you to provide your settings to Ruff. Here\u0026rsquo;s how I believe is best.\nOne of the coolest features of Ruff is you can define your linting and formatting settings in your pyproject.toml. This way, everyone working on your repository can have the same warnings and such.\nAdditionally, you can define these same settings in your editor. By default, your editor settings take precedent over your pyproject.toml settings.\nI like the idea of taking on the settings of whatever project I\u0026rsquo;m working on, but then \u0026ldquo;falling back\u0026rdquo; to my settings when I\u0026rsquo;m working on my own scripts. We can accomplish this with the following setting\n{ \u0026#34;ruff.configurationPreference\u0026#34;: \u0026#34;filesystemFirst\u0026#34;, } Defining pyproject.toml settings [tool.ruff] line-length = 88 indent-width = 4 target-version = \u0026#34;py39\u0026#34; [tool.ruff.lint] select = [\u0026#34;E4\u0026#34;, \u0026#34;E7\u0026#34;, \u0026#34;E9\u0026#34;, \u0026#34;F\u0026#34;] ignore = [] fixable = [\u0026#34;ALL\u0026#34;] [tool.ruff.format] quote-style = \u0026#34;double\u0026#34; indent-style = \u0026#34;space\u0026#34; Defining editor settings The ruff extensions exposes a few common configs through the settings, like so\n// settings.json { \u0026#34;ruff.lineLength\u0026#34;: 110, \u0026#34;ruff.lint.select\u0026#34;: [\u0026#34;ALL\u0026#34;], \u0026#34;ruff.lint.ignore\u0026#34;: [\u0026#34;E501\u0026#34;], } For more granular (and more pyproject-like) settings, you can\n// settings.json { \u0026#34;ruff.configuration\u0026#34;: { \u0026#34;lint\u0026#34;: { \u0026#34;unfixable\u0026#34;: [\u0026#34;F401\u0026#34;], \u0026#34;extend-select\u0026#34;: [\u0026#34;TID251\u0026#34;], }, \u0026#34;format\u0026#34;: { \u0026#34;quote-style\u0026#34;: \u0026#34;single\u0026#34; } } } Format on save with Ruff The following settings.json entries trigger Ruff\u0026rsquo;s formatting and import sorting every time you save a Python file:\n{ \u0026#34;[python]\u0026#34;: { \u0026#34;editor.codeActionsOnSave\u0026#34;: { \u0026#34;source.organizeImports.ruff\u0026#34;: \u0026#34;always\u0026#34; }, \u0026#34;editor.defaultFormatter\u0026#34;: \u0026#34;charliermarsh.ruff\u0026#34;, \u0026#34;editor.formatOnSave\u0026#34;: true } } Optional: Disable “disable rule” code actions If you use and abuse Ctrl+. to trigger code actions like me, Ruff\u0026rsquo;s “disable this rule” suggestions can add quite a bit of clutter. You can disable these code actions with the following:\n{ \u0026#34;ruff.codeAction.disableRuleComment\u0026#34;: { \u0026#34;enable\u0026#34;: false } } Binding auto fix to shortcuts I personally don\u0026rsquo;t like the \u0026ldquo;auto fix on save\u0026rdquo; feature as I save often, and Ruff would remove my unused-but-still-needed imports.\nInstead, I set up a keybinding in VSCodeVim to run Ruff fixes manually.\nVSCodeVim:\n{ // settings.json \u0026#34;vim.normalModeKeyBindings\u0026#34;: [ // \u0026#34;[r]uff [f]ix\u0026#34; { \u0026#34;before\u0026#34;: [ \u0026#34;r\u0026#34;, \u0026#34;f\u0026#34; ], \u0026#34;commands\u0026#34;: [ \u0026#34;ruff.executeAutofix\u0026#34;, \u0026#34;workbench.action.files.save\u0026#34; ] }, ] } Regular VSCode keybindings:\n{ // keybindings.json { \u0026#34;key\u0026#34;: \u0026#34;ctrl+shift+f\u0026#34;, \u0026#34;command\u0026#34;: \u0026#34;ruff.executeAutofix\u0026#34; } } ","permalink":"https://bexli.dev/posts/vscode/ruff-vscode/","summary":"Configuring Ruff for VSCode","title":"Ruff + VSCode"},{"content":"Site meta Generated by Hugo Themed by Catppuccin-ized custom PaperMod Hosted on Github Pages via Actions ","permalink":"https://bexli.dev/about/","summary":"About","title":"About"}]