Mike Slinn

Essential Visual Studio Code Extensions for Ruby

Published 2022-02-20. Last modified 2024-02-21.
Time to read: 8 minutes.

This page is part of the ruby collection.

For best results, install virtualized Ruby using rbenv before attempting to follow these instructions.

In mid-July 2023, Ruby LSP became the official Ruby plugin for Ruby development with Visual Studio Code. This is the GitHub project. The Ruby LSP documentation can be difficult to find.

Remove Old Ruby Extensions

Previously popular Visual Studio Code extensions for working with Ruby do not coexist with Ruby LSP. Remove them:

Installing Debug Support

Debugging Components

A diagram should help us understand how the different components of a Ruby debugging extension work for Visual Studio Code. I added Ruby components to a diagram provided in Introducing Logpoints and auto-attach from the Visual Studio Code documentation. Various implementations of debug adapters are listed here; we will use the VSCode rdbg Ruby Debugger.

You can see several components in the above diagram:

  1. The Ruby LSP Visual Studio Code plugin, which provides debugging, lint, semantic highlighting, and Intellisense support for Ruby. (The diagram just lumps this plugin with the Debugger UI).
  2. The vscode-rdbg gem, which uses the debug adaptor protocol to communicate between Visual Studio and the debug gem, which provides the rdbg debugger for Ruby.
  3. The Ruby runtime.

Command-Line Debugger

Command-line debug support for Ruby is provided by the debug Ruby gem. This gem installs the rdbg command. Debug must be installed separately before the Visual Studio Code extension can debug Ruby code:

Shell
$ gem install debug
Building native extensions. This could take a while...
Successfully installed debug-1.8.0
Parsing documentation for debug-1.8.0
Done installing documentation for debug after 1 seconds
1 gem installed 

Verify you have at least version 1.8.0:

Shell
$ gem info debug
*** LOCAL GEMS ***
debug (1.8.0, 1.7.1, 1.6.1, 1.5.0, 1.4.0) Author: Koichi Sasada Homepage: https://github.com/ruby/debug Licenses: Ruby, BSD-2-Clause Installed at (1.8.0): /home/mslinn/.rbenv/versions/3.1.0/lib/ruby/gems/3.1.0 (1.7.1): /home/mslinn/.rbenv/versions/3.1.0/lib/ruby/gems/3.1.0 (1.6.1): /home/mslinn/.rbenv/versions/3.1.0/lib/ruby/gems/3.1.0 (1.5.0): /home/mslinn/.rbenv/versions/3.1.0/lib/ruby/gems/3.1.0 (1.4.0): /home/mslinn/.rbenv/versions/3.1.0/lib/ruby/gems/3.1.0
Debugging functionality for Ruby

Ensure that the rdbg command that the debug gem provides is on the PATH:

Shell
$ which rdbg
/home/mslinn/.rbenv/shims/rdbg 

Help message:

Shell
$ rdbg -h
rdbg [options] -- [debuggee options]
Debug console mode: -n, --nonstop Do not stop at the beginning of the script. -e DEBUG_COMMAND Execute debug command at the beginning of the script. -x, --init-script=FILE Execute debug command in the FILE. --no-rc Ignore ~/.rdbgrc --no-color Disable colorize --no-sigint-hook Disable to trap SIGINT -c, --command Enable command mode. The first argument should be a command name in $PATH. Example: 'rdbg -c bundle exec rake test'
-O, --open=[FRONTEND] Start remote debugging with opening the network port. If TCP/IP options are not given, a UNIX domain socket will be used. If FRONTEND is given, prepare for the FRONTEND. Now rdbg, vscode and chrome is supported. --sock-path=SOCK_PATH UNIX Domain socket path --port=PORT Listening TCP/IP port --host=HOST Listening TCP/IP host --cookie=COOKIE Set a cookie for connection
Debug console mode runs Ruby program with the debug console.
'rdbg target.rb foo bar' starts like 'ruby target.rb foo bar'. 'rdbg -- -r foo -e bar' starts like 'ruby -r foo -e bar'. 'rdbg -c rake test' starts like 'rake test'. 'rdbg -c -- rake test -t' starts like 'rake test -t'. 'rdbg -c bundle exec rake test' starts like 'bundle exec rake test'. 'rdbg -O target.rb foo bar' starts and accepts attaching with UNIX domain socket. 'rdbg -O --port 1234 target.rb foo bar' starts accepts attaching with TCP/IP localhost:1234. 'rdbg -O --port 1234 -- -r foo -e bar' starts accepts attaching with TCP/IP localhost:1234. 'rdbg target.rb -O chrome --port 1234' starts and accepts connecting from Chrome Devtools with localhost:1234.
Attach mode: -A, --attach Attach to debuggee process.
Attach mode attaches the remote debug console to the debuggee process.
'rdbg -A' tries to connect via UNIX domain socket. If there are multiple processes are waiting for the debugger connection, list possible debuggee names. 'rdbg -A path' tries to connect via UNIX domain socket with given path name. 'rdbg -A port' tries to connect to localhost:port via TCP/IP. 'rdbg -A host port' tries to connect to host:port via TCP/IP.
Other options: -v Show version number --version Show version number and exit -h, --help Print help --util=NAME Utility mode (used by tools) --stop-at-load Stop immediately when the debugging feature is loaded.
NOTE All messages communicated between a debugger and a debuggee are *NOT* encrypted. Please use the remote debugging feature carefully.

Visual Studio vscode-rdbg Extension

You also need to install the Visual Studio RDBG extension.

There is also an old extension called Ruby Debug, by Castwide. DO NOT INSTALL IT! REMOVE IT IF PRESENT. This old extension is easily confused with the VSCode extension you should install, VSCode rdbg Ruby Debugger by Koichi Sasada.

Rdbg v0.1.0 Works Better than v2.1.0

One of my computers will NOT run Koichi Sasada’s extension. Other computers work fine. I have no idea why. It seems other people have had this problem as well. The little blue spinner below the run button would never stop, and I would have to exit VSCode before trying again. I spent hours trying to get the blessed thing to work. Finally, I downgraded from v0.2.1, to v0.2.0, and finally to v0.1.0, and that version worked.

This is how to download and install v0.1.0 of Koichi Sasada’s extension:

  1. Open the Extensions view in the Visual Studio Code primary sidebar.
  2. Find the extension that you installed called VSCode rdbg Ruby Debugger.
  3. Hover over the extension panel and an information panel will appear to the right, showing the currently installed version and the latest available version.

    The above shows that v0.1.0 is installed, and v0.2.1 is available. This is actually the version you want installed, so if you see this there is no need to continue. However, if a different version is installed, please continue.
  4. Right-click on the extension and select Install Another Version... from the menu that appears.

  5. The Visual Studio Code Activity Bar will now show you all available versions of the extension.

    Select version 0.1.0.

Because Visual Studio Code auto-updates all extensions by default, Ruby debugging may suddenly cease to work without warning. Read on to learn how to fix that.

Before Visual Studio Code v1.85.0, released on October 8, 2023, you could only enable or suppress the auto-updating of all extensions. This is accomplished by bringing up the control palette (CTRL-Shift-P) and then typing Extensions: Disable Auto Updating Extensions. You can update any of the other plugins manually; doing so will not cause rdbg to be updated.

Visual Studio Code v1.85.0 introduced extension auto update control. Instead of using the Visual Studio Code control palette, the More actions icon of the Extensions tab can be used to display the Auto Update Extensions menu. The icon looks like three dots, as shown in the image below. I have numbered where you need to click, in order, to selectively enable extension auto-update.

Unfortunately, the control is the opposite of what we need and necessitates that you manually enable updates for dozens of extensions. I submitted an enhancement request. The following is an explanation of how to use the feature as it currently exists.

Using the control palette as described above to disable extension auto-update causes the Auto Update Extensions menu to be set to None. You want it to be set to Selected Extensions instead, then you can selectively enable extensions to auto-update by right-clicking on an extension and either selecting Auto Update or Auto Update All (From Publisher). Do this for all extensions except rdbg.

You can also enable auto-update for the currently displayed extension:

VS Code prompts a user to install the recommended extensions when a workspace is opened for the first time. The user can also review the list with the Extensions: Show Recommended Extensions command. Define the recommended extensions by storing the following into your projects’s .vscode/extensions.json:

.vscode/extensions.json
{
  // See https://go.microsoft.com/fwlink/?LinkId=827846 to learn about workspace recommendations.

  // List of recommended extensions for this workspace.
  "recommendations": [
    "DavidAnson.vscode-markdownlint",
    "devonray.snippet",
    "groksrc.ruby",
    "KoichiSasada.vscode-rdbg",
    "hoovercj.ruby-linter",
    "miguel-savignano.ruby-symbols",
    "misogi.ruby-rubocop",
    "neilding.language-liquid",
    "redhat.vscode-yaml",
    "shd101wyy.markdown-preview-enhanced",
    "Shopify.ruby-extensions-pack",
    "Shopify.ruby-lsp",
    "sissel.shopify-liquid",
    "timonwong.shellcheck",
    "vayan.haml",
    "vortizhe.simple-ruby-erb",
  ],
  // List of extensions that should be removed.
  "unwantedRecommendations": [
    "castwide.solargraph",
    "rebornix.Ruby",
    "wingrunr21.vscode-ruby",
  ]
}

Settings

User Settings

User settings for Visual Studio Code are stored in a file called settings.json. The paths for that file differ for each OS that Visual Studio Code runs on.

Windows: %AppData%\Code\User\settings.json
Linux: $HOME/.config/Code/User/settings.json

The following are the Ruby-specific settings that I use:

settings.json fragment
{ 
  "[ruby]": {
    "editor.defaultFormatter": "Shopify.ruby-lsp",
    "editor.formatOnSave": true,
    "editor.formatOnType": true,
    "editor.tabSize": 2,
    "editor.insertSpaces": true,
    "editor.semanticHighlighting.enabled": true
  },
  "debug.console.fontSize": 18,
  "debug.onTaskErrors": "abort",
  "debug.terminal.clearBeforeReusing": true,
  "ruby.rubocop.executePath": "/home/mslinn/.rbenv/shims/",
  "ruby.rubocop.useBundler": true,
  "rubyLsp.enableExperimentalFeatures": true,
  "rubyLsp.enabledFeatures": {
    "codeActions": true,
    "diagnostics": true,
    "documentHighlights": true,
    "documentLink": true,
    "documentSymbols": true,
    "foldingRanges": true,
    "formatting": true,
    "hover": true,
    "inlayHint": true,
    "onTypeFormatting": true,
    "selectionRanges": true,
    "semanticHighlighting": true,
    "completion": true,
    "codeLens": true,
    "definition": true,
    "workspaceSymbol": true
  },
  "rubyLsp.formatter": "auto",
  "rubyLsp.rubyVersionManager": "rbenv",
  "telemetry.telemetryLevel": "off",
} 

WSL Settings

WSL settings override user settings. They are stored in $HOME/.vscode-server/data/Machine/settings.json. If adjusting user settings does not change behavior, examine WSL settings for a conflict.

Debugging

The ruby_lsp type of launch configuration uses rdbg, and it does that by launching a shell, which is slow. So anything you can do with the ruby_lsp launch type can also be done with the rdbg launch type, and using the rdbg launch type will be faster.

The ruby_lsp launch type is simpler to use than the rdbg launch type, but is less flexible and slower. I prefer to debug Ruby programs by directly using rdbg instead of ruby_lsp, but the rdbg documentation is poorly written, contains unmentioned assumptions, and contains errors. The next few sections contain a heavily edited version of the published documentation for the Visual Studio Code rdbg launch.json options.

Debuggee Launch Configuration Settings

Automatically created launch configuration settings for rdbg do not work on WSL/Ubuntu. Read on to learn what is needed; I highlighted the most important points.

Definition: the debuggee is just the program to be debugged.

script
The file name of the script to run. Default: the name of the active Ruby file in Visual Studio Code.
command
An executable Ruby command. For example, you can specify ~/.rbenv/shims/ruby. Default: ruby (which is found along the PATH).
cwd
Directory to execute the program in. Default: ${workspaceFolder}
args
The command line arguments passed to the program, as an array of strings. Default: []
env
Additional environment variables to pass to the debugging (and debugged) process. Default: []
useBundler
Invoke Ruby programs with bundle exec. The default value for this option is true if a file called Gemfile is present in the directory tree where the script to execute resides; otherwise, the default value is false.

Behavior settings

askParameters

Causes the user to be prompted for the entire command line before debugging. The response is remembered and offered as the value for the next launch. If the command line is always the same, use the other options to specify the command line instead of using this option.

For example, given the first launch configuration (EXPERIMENT) in the next section below and with the knowledge that the target directory contains a file called Gemfile, the value offered to the user is:

bundle exec ruby /mslinn.com/blog/bin/gitUrls.rb $sitesUbuntu

rdbgPath
Full path of the rdbg executable. Default: use the PATH to locate rdbg.
debugPort
This option specifies how to communicate with the debuggee.

The default for most OSes is to open a UNIX Domain Socket, except for Windows, which defaults to opening a TCP/IP socket at localhost:0. If the option is specified as a numeric string (e.g., "12345"), then a TCP/IP debug port on localhost is opened with that value. If the option is specified as hostname:port (e.g., "hostname:12345"), then a TCP/IP port on the specified remote host is opened using the given port.

You can specify that an unused port should be automatically chosen if the value of this option is set to "0"; this requires v1.5.0+ of the debug gem. Version 1.5.0 was released on March 30, 2022, so you probably have a newer version. I have found that setting this value to "0" is the most reliable option when debugging on localhost, and that this option must be specified when running on WSL/Ubuntu.
waitLaunchTime
This option is not required when using debug gem v1.5.0+. Opening a TCP/IP debug port requires a short delay for the operation to complete before the port can be used. By default, a 5000-millisecond (5 second) delay is used.
useTerminal
If your program needs to read from STDIN, set this option. By default, all outputs to STDIN and STDOUT are shown in the debug console. This option creates a new terminal for executing the debug command. The creation process takes extra time.
showProtocolLog
This option causes all DAP communication to be displayed. Default: false

Enable this option to debug your launch configuration.
When I use this option under WSL/Ubuntu, I see the following message on each launch. The message does not appear to be important; just ignore it:
bash: initialize_job_control: no job control in background: Bad file descriptor

Example Launch Configurations

.vscode/launch.json
{
  "version": "0.2.0",
  "configurations": [
    {
      "args": [ "$sitesUbuntu" ],
      "debugPort": "0",
      "name": "EXPERIMENT",
      "request": "launch",
      "script": "${workspaceRoot}/blog/bin/gitUrls.rb",
      "showProtocolLog": true,
      "type": "rdbg",
    },
      {
      "debugPort": "0",
      "name": "Debug abc.rb with rdbg",
      "request": "launch",
      "script": "${workspaceRoot}lib/abc.rb",
      "type": "rdbg",
    },
    {
      "debugPort": "0",
      "name": "Debug current file with rdbg",
      "request": "launch",
      "script": "${file}",
      "type": "rdbg",
    },
    {
      "name": "Attach with rdbg",
      "debugPort": "0",
      "request": "attach",
      "type": "rdbg",
    },
    {
      "args": [],
      "command": "rake",
      "debugPort": "0",
      "name": "Run rake test",
      "request": "launch",
      "script": "test", // launch rake test with debugger
      "type": "rdbg",
    },
    {
      "args": [
        "serve",
        "--livereload_port", "35721",
        "--force_polling",
        "--host", "0.0.0.0",
        "--port", "4001",
        "--future",
        "--incremental",
        "--livereload",
        "--drafts",
        "--unpublished"
      ],
      "debugPort": "0",
      "name": "Debug Jekyll",
      "request": "launch",
      "script": "./exe/jekyll",
      "type": "rdbg",
    },
  ]
}

When I use the first launch configuration above, called EXPERIMENT, the following appears in the Visual Studio Code output panel because showProtocolLog is enabled:

Shell
"Running: /bin/bash -lic rdbg --command --open --stop-at-load --host=localhost --port=0 -- bundle exec ruby /var/sitesUbuntu/www.mslinn.com/blog/bin/gitUrls.rb $sitesUbuntu"
bash: initialize_job_control: no job control in background: Bad file descriptor

[Start session]
{"d":{},"f":"b8cde853-5fbd-4df3-a99f-463a1e68d2fa","g":"rdbg","h":"EXPERIMENT Debug gitUrls.rb with rdbg","i":{"uri":{"$mid":1,"fsPath":"/var/sitesUbuntu/www.mslinn.com","external":"file:///var/sitesUbuntu/www.mslinn.com","path":"/var/sitesUbuntu/www.mslinn.com","scheme":"file"},"name":"www.mslinn.com","index":0},"j":{"args":["$sitesUbuntu"],"debugPort":"0","name":"EXPERIMENT Debug gitUrls.rb with rdbg","request":"launch","script":"/var/sitesUbuntu/www.mslinn.com/blog/bin/gitUrls.rb","showProtocolLog":true,"type":"rdbg","__configurationTarget":6,"rdbgExtensions":["traceInspector"],"rdbgInitialScripts":[]}}
[VSCode->DA] {"command":"initialize","arguments":{"clientID":"vscode","clientName":"Visual Studio Code","adapterID":"rdbg","pathFormat":"path","linesStartAt1":true,"columnsStartAt1":true,"supportsVariableType":true,"supportsVariablePaging":true,"supportsRunInTerminalRequest":true,"locale":"en","supportsProgressReporting":true,"supportsInvalidatedEvent":true,"supportsMemoryReferences":true,"supportsArgsCanBeInterpretedByShell":true,"supportsMemoryEvent":true,"supportsStartDebuggingRequest":true},"type":"request","seq":1}
[DA->VSCode] {"type":"response","command":"initialize","request_seq":1,"success":true,"message":"Success","body":{"supportsConfigurationDoneRequest":true,"supportsFunctionBreakpoints":true,"supportsConditionalBreakpoints":true,"supportTerminateDebuggee":true,"supportsTerminateRequest":true,"exceptionBreakpointFilters":[{"filter":"any","label":"rescue any exception","supportsCondition":true},{"filter":"RuntimeError","label":"rescue RuntimeError","supportsCondition":true}],"supportsExceptionFilterOptions":true,"supportsStepBack":true,"supportsEvaluateForHovers":true,"supportsCompletionsRequest":true},"seq":1}
[DA->VSCode] {"type":"event","event":"initialized","seq":2}
[DA->VSCode] {"type":"event","event":"output","body":{"category":"console","output":"Ruby REPL: You can run any Ruby expression here.\nNote that output to the STDOUT/ERR printed on the TERMINAL.\n[experimental]\n  `,COMMAND` runs `COMMAND` debug command (ex: `,info`).\n  `,help` to list all debug commands.\n"},"seq":3}
[VSCode->DA] {"command":"launch","arguments":{"args":["$sitesUbuntu"],"debugPort":"0","name":"EXPERIMENT Debug gitUrls.rb with rdbg","request":"launch","script":"/var/sitesUbuntu/www.mslinn.com/blog/bin/gitUrls.rb","showProtocolLog":true,"type":"rdbg","__configurationTarget":6,"rdbgExtensions":["traceInspector"],"rdbgInitialScripts":[],"__sessionId":"b8cde853-5fbd-4df3-a99f-463a1e68d2fa"},"type":"request","seq":2}
[VSCode->DA] {"command":"setBreakpoints","arguments":{"source":{"name":"categorized_under.rb","path":"/var/sitesUbuntu/www.mslinn.com/_plugins/categorized_under.rb"},"lines":[34],"breakpoints":[{"line":34}],"sourceModified":false},"type":"request","seq":3}
[VSCode->DA] {"command":"setBreakpoints","arguments":{"source":{"name":"configuration.rb","path":"/home/mslinn/.rbenv/versions/3.1.0/lib/ruby/gems/3.1.0/gems/jekyll-4.2.2/lib/jekyll/configuration.rb"},"lines":[],"breakpoints":[],"sourceModified":false},"type":"request","seq":4}
[VSCode->DA] {"command":"setBreakpoints","arguments":{"source":{"name":"gitUrls.rb","path":"/var/sitesUbuntu/www.mslinn.com/blog/bin/gitUrls.rb"},"lines":[46],"breakpoints":[{"line":46}],"sourceModified":false},"type":"request","seq":5}
[VSCode->DA] {"command":"setBreakpoints","arguments":{"source":{"name":"jekyll_plugins","path":"/var/sitesUbuntu/www.mslinn.com/blog/bin/jekyll_plugins"},"lines":[],"breakpoints":[],"sourceModified":false},"type":"request","seq":6}
[VSCode->DA] {"command":"setBreakpoints","arguments":{"source":{"name":"makeAwsBucket","path":"/var/sitesUbuntu/www.mslinn.com/_bin/makeAwsBucket"},"lines":[],"breakpoints":[],"sourceModified":false},"type":"request","seq":7}
[VSCode->DA] {"command":"setBreakpoints","arguments":{"source":{"name":"outline.rb","path":"/var/sitesUbuntu/www.mslinn.com/_plugins/outline.rb"},"lines":[],"breakpoints":[],"sourceModified":false},"type":"request","seq":8}
[VSCode->DA] {"command":"setBreakpoints","arguments":{"source":{"name":"run.rb","path":"/var/sitesUbuntu/www.mslinn.com/_plugins/run.rb"},"lines":[],"breakpoints":[],"sourceModified":false},"type":"request","seq":9}
[VSCode->DA] {"command":"setBreakpoints","arguments":{"source":{"name":"site_inspector.rb","path":"/var/sitesUbuntu/www.mslinn.com/_plugins/site_inspector.rb"},"lines":[],"breakpoints":[],"sourceModified":false},"type":"request","seq":10}
[VSCode->DA] {"command":"setBreakpoints","arguments":{"source":{"name":"site.rb","path":"/home/mslinn/.rbenv/versions/2.7.2/lib/ruby/gems/2.7.0/gems/jekyll-4.2.2/lib/jekyll/site.rb"},"lines":[],"breakpoints":[],"sourceModified":false},"type":"request","seq":11}
[VSCode->DA] {"command":"setFunctionBreakpoints","arguments":{"breakpoints":[]},"type":"request","seq":12}
[VSCode->DA] {"command":"setExceptionBreakpoints","arguments":{"filters":[],"filterOptions":[]},"type":"request","seq":13}
[DA->VSCode] {"type":"response","command":"launch","request_seq":2,"success":true,"message":"Success","seq":4}
[DA->VSCode] {"type":"response","command":"setBreakpoints","request_seq":3,"success":true,"message":"Success","body":{"breakpoints":[{"verified":true}]},"seq":5}
[DA->VSCode] {"type":"response","command":"setBreakpoints","request_seq":4,"success":true,"message":"Success","body":{"breakpoints":[]},"seq":6}
[DA->VSCode] {"type":"response","command":"setBreakpoints","request_seq":5,"success":true,"message":"Success","body":{"breakpoints":[{"verified":true}]},"seq":7}
[DA->VSCode] {"type":"response","command":"setBreakpoints","request_seq":6,"success":true,"message":"Success","body":{"breakpoints":[]},"seq":8}
[DA->VSCode] {"type":"response","command":"setBreakpoints","request_seq":7,"success":true,"message":"Success","body":{"breakpoints":[]},"seq":9}
[DA->VSCode] {"type":"response","command":"setBreakpoints","request_seq":8,"success":true,"message":"Success","body":{"breakpoints":[]},"seq":10}
[DA->VSCode] {"type":"response","command":"setBreakpoints","request_seq":9,"success":true,"message":"Success","body":{"breakpoints":[]},"seq":11}
[DA->VSCode] {"type":"response","command":"setBreakpoints","request_seq":10,"success":true,"message":"Success","body":{"breakpoints":[]},"seq":12}
[DA->VSCode] {"type":"response","command":"setBreakpoints","request_seq":11,"success":true,"message":"Success","body":{"breakpoints":[]},"seq":13}
[DA->VSCode] {"type":"response","command":"setFunctionBreakpoints","request_seq":12,"success":true,"message":"Success","seq":14}
[DA->VSCode] {"type":"response","command":"setExceptionBreakpoints","request_seq":13,"success":true,"message":"Success","body":{"breakpoints":[]},"seq":15}
[VSCode->DA] {"command":"evaluate","arguments":{"expression":",eval $stdout.sync=true","context":"repl"},"type":"request","seq":14}
[DA->VSCode] {"type":"response","command":"evaluate","request_seq":14,"success":true,"message":"Success","body":{"result":"(rdbg:command) eval $stdout.sync=true","variablesReference":0},"seq":16}
[VSCode->DA] {"command":"configurationDone","type":"request","seq":15}
[DA->VSCode] {"type":"response","command":"configurationDone","request_seq":15,"success":true,"message":"Success","seq":17}
[DA->VSCode] {"type":"event","event":"loadedSource","body":{"reason":"new","source":{"path":"/var/sitesUbuntu/www.mslinn.com/blog/bin/gitUrls.rb"}},"seq":18}
[DA->VSCode] {"type":"event","event":"loadedSource","body":{"reason":"new","source":{"path":"/home/mslinn/.rbenv/versions/3.1.0/lib/ruby/gems/3.1.0/gems/rugged-1.6.3/lib/rugged.rb"}},"seq":19}
[DA->VSCode] {"type":"event","event":"loadedSource","body":{"reason":"new","source":{"path":"/home/mslinn/.rbenv/versions/3.1.0/lib/ruby/gems/3.1.0/gems/rugged-1.6.3/lib/rugged/index.rb"}},"seq":20}
[DA->VSCode] {"type":"event","event":"loadedSource","body":{"reason":"new","source":{"path":"/home/mslinn/.rbenv/versions/3.1.0/lib/ruby/gems/3.1.0/gems/rugged-1.6.3/lib/rugged/object.rb"}},"seq":21}
[DA->VSCode] {"type":"event","event":"loadedSource","body":{"reason":"new","source":{"path":"/home/mslinn/.rbenv/versions/3.1.0/lib/ruby/gems/3.1.0/gems/rugged-1.6.3/lib/rugged/commit.rb"}},"seq":22}
[DA->VSCode] {"type":"event","event":"loadedSource","body":{"reason":"new","source":{"path":"/home/mslinn/.rbenv/versions/3.1.0/lib/ruby/gems/3.1.0/gems/rugged-1.6.3/lib/rugged/version.rb"}},"seq":23}
[DA->VSCode] {"type":"event","event":"loadedSource","body":{"reason":"new","source":{"path":"/home/mslinn/.rbenv/versions/3.1.0/lib/ruby/gems/3.1.0/gems/rugged-1.6.3/lib/rugged/repository.rb"}},"seq":24}
[DA->VSCode] {"type":"event","event":"loadedSource","body":{"reason":"new","source":{"path":"/home/mslinn/.rbenv/versions/3.1.0/lib/ruby/gems/3.1.0/gems/rugged-1.6.3/lib/rugged/reference.rb"}},"seq":25}
[DA->VSCode] {"type":"event","event":"loadedSource","body":{"reason":"new","source":{"path":"/home/mslinn/.rbenv/versions/3.1.0/lib/ruby/gems/3.1.0/gems/rugged-1.6.3/lib/rugged/walker.rb"}},"seq":26}
[DA->VSCode] {"type":"event","event":"loadedSource","body":{"reason":"new","source":{"path":"/home/mslinn/.rbenv/versions/3.1.0/lib/ruby/gems/3.1.0/gems/rugged-1.6.3/lib/rugged/tree.rb"}},"seq":27}
[DA->VSCode] {"type":"event","event":"loadedSource","body":{"reason":"new","source":{"path":"/home/mslinn/.rbenv/versions/3.1.0/lib/ruby/gems/3.1.0/gems/rugged-1.6.3/lib/rugged/tag.rb"}},"seq":28}
[DA->VSCode] {"type":"event","event":"loadedSource","body":{"reason":"new","source":{"path":"/home/mslinn/.rbenv/versions/3.1.0/lib/ruby/gems/3.1.0/gems/rugged-1.6.3/lib/rugged/branch.rb"}},"seq":29}
[DA->VSCode] {"type":"event","event":"loadedSource","body":{"reason":"new","source":{"path":"/home/mslinn/.rbenv/versions/3.1.0/lib/ruby/gems/3.1.0/gems/rugged-1.6.3/lib/rugged/diff.rb"}},"seq":30}
[DA->VSCode] {"type":"event","event":"loadedSource","body":{"reason":"new","source":{"path":"/home/mslinn/.rbenv/versions/3.1.0/lib/ruby/gems/3.1.0/gems/rugged-1.6.3/lib/rugged/diff/hunk.rb"}},"seq":31}
[DA->VSCode] {"type":"event","event":"loadedSource","body":{"reason":"new","source":{"path":"/home/mslinn/.rbenv/versions/3.1.0/lib/ruby/gems/3.1.0/gems/rugged-1.6.3/lib/rugged/diff/line.rb"}},"seq":32}
[DA->VSCode] {"type":"event","event":"loadedSource","body":{"reason":"new","source":{"path":"/home/mslinn/.rbenv/versions/3.1.0/lib/ruby/gems/3.1.0/gems/rugged-1.6.3/lib/rugged/diff/delta.rb"}},"seq":33}
[DA->VSCode] {"type":"event","event":"loadedSource","body":{"reason":"new","source":{"path":"/home/mslinn/.rbenv/versions/3.1.0/lib/ruby/gems/3.1.0/gems/rugged-1.6.3/lib/rugged/patch.rb"}},"seq":34}
[DA->VSCode] {"type":"event","event":"loadedSource","body":{"reason":"new","source":{"path":"/home/mslinn/.rbenv/versions/3.1.0/lib/ruby/gems/3.1.0/gems/rugged-1.6.3/lib/rugged/remote.rb"}},"seq":35}
[DA->VSCode] {"type":"event","event":"loadedSource","body":{"reason":"new","source":{"path":"/home/mslinn/.rbenv/versions/3.1.0/lib/ruby/gems/3.1.0/gems/rugged-1.6.3/lib/rugged/credentials.rb"}},"seq":36}
[DA->VSCode] {"type":"event","event":"loadedSource","body":{"reason":"new","source":{"path":"/home/mslinn/.rbenv/versions/3.1.0/lib/ruby/gems/3.1.0/gems/rugged-1.6.3/lib/rugged/attributes.rb"}},"seq":37}
[DA->VSCode] {"type":"event","event":"loadedSource","body":{"reason":"new","source":{"path":"/home/mslinn/.rbenv/versions/3.1.0/lib/ruby/gems/3.1.0/gems/rugged-1.6.3/lib/rugged/blob.rb"}},"seq":38}
[DA->VSCode] {"type":"event","event":"loadedSource","body":{"reason":"new","source":{"path":"/home/mslinn/.rbenv/versions/3.1.0/lib/ruby/gems/3.1.0/gems/rugged-1.6.3/lib/rugged/submodule_collection.rb"}},"seq":39}
[DA->VSCode] {"type":"event","event":"stopped","body":{"reason":"breakpoint","description":" BP - Line  /var/sitesUbuntu/www.mslinn.com/blog/bin/gitUrls.rb:46 (line)","text":" BP - Line  /var/sitesUbuntu/www.mslinn.com/blog/bin/gitUrls.rb:46 (line)","threadId":1,"allThreadsStopped":true},"seq":40}
[VSCode->DA] {"command":"threads","type":"request","seq":16}
[DA->VSCode] {"type":"response","command":"threads","request_seq":16,"success":true,"message":"Success","body":{"threads":[{"id":1,"name":"#1 /var/sitesUbuntu/www.mslinn.com/blog/bin/gitUrls.rb:46:in `
'"}]},"seq":41} [VSCode->DA] {"command":"threads","type":"request","seq":17} [DA->VSCode] {"type":"response","command":"threads","request_seq":17,"success":true,"message":"Success","body":{"threads":[{"id":1,"name":"#1 /var/sitesUbuntu/www.mslinn.com/blog/bin/gitUrls.rb:46:in `
'"}]},"seq":42} [VSCode->DA] {"command":"stackTrace","arguments":{"threadId":1,"startFrame":0,"levels":20},"type":"request","seq":18} [DA->VSCode] {"type":"response","command":"stackTrace","request_seq":18,"success":true,"message":"Success","body":{"stackFrames":[{"id":1,"name":"
","line":46,"column":1,"source":{"name":"gitUrls.rb","path":"/var/sitesUbuntu/www.mslinn.com/blog/bin/gitUrls.rb","sourceReference":0}}],"totalFrames":1},"seq":43} [VSCode->DA] {"command":"setBreakpoints","arguments":{"source":{"path":"/var/sitesUbuntu/www.mslinn.com/blog/bin/gitUrls.rb","name":"gitUrls.rb","sourceReference":0},"lines":[],"breakpoints":[],"sourceModified":false},"type":"request","seq":19} [DA->VSCode] {"type":"response","command":"setBreakpoints","request_seq":19,"success":true,"message":"Success","body":{"breakpoints":[]},"seq":44} [VSCode->DA] {"command":"continue","arguments":{"threadId":1},"type":"request","seq":20} [DA->VSCode] {"type":"response","command":"continue","request_seq":20,"success":true,"message":"Success","body":{"allThreadsContinued":true},"seq":45} [DA->VSCode] {"type":"event","event":"terminated","seq":46} [Error on session] Error: connection closed e: {} [VSCode->DA] {"command":"disconnect","arguments":{"restart":false,"terminateDebuggee":false},"type":"request","seq":21}

Jekyll Plugins

If you use Visual Studio Code, and you work in Ruby because you maintain a Jekyll website, you might find the following VS Code extensions helpful.

  1. Liquid provides syntax highlighting, formatting and snippet support for the liquid template language. Supports both Jekyll and Shopify variations.
  2. jekyll-run VS Code plugin.
  3. Jekyll snippets for Visual Studio Code is a combination of both the sublime-jekyll package by @23maverick23 and the atom-jekyll package by @jasonhodges.
  4. jekyll-post makes it easier to create new articles for Jekyll-based websites using the Visual Studio Code editor. Using this extension, a user can create a new file with pre-filled ‘front matter’. The template for front matter can either be provided by the user, or the extension will use its built-in template.

Debugging an Installed Gem

Sometimes it is helpful to be able to debug an installed gem.

You can discover where a gem is installed by using bundle info --path and adding the name of the gem.

Shell
$ bundle info --path jekyll_plugin_support
/home/mslinn/.rbenv/versions/3.1.2/lib/ruby/gems/3.1.0/gems/jekyll_plugin_support-0.8.3 

The installed gem can be loaded into Visual Studio Code by typing code -a and providing the path to the gem that you just obtained.

Shell
$ code -a /home/mslinn/.rbenv/versions/3.1.2/lib/ruby/gems/3.1.0/gems/jekyll_plugin_support-0.8.3

Here is a script that performs the above:

#!/usr/bin/env ruby

require 'open3'

def help
  progname = File.basename $PROGRAM_NAME
  printf <<~END_MSG
    #{progname} - edit installed gem in Visual Studio Code

    Syntax:
      #{progname} GEM_NAME
  END_MSG
  exit 1
end

# @return String array containing resulting lines of running command
def run_capture_stdout(command)
  # printf "Run #{command}\n".yellow
  stdout_str, status = Open3.capture2 command
  unless status.success?
    printf "Error: #{command} returned #{status}"
    exit status.to_i
  end
  stdout_str.strip.split
end

help if ARGV.empty?
help if ARGV.length > 1
gem_path = run_capture_stdout("bundle info --path #{ARGV[0]}").first
puts "Editing #{gem_path}"

`code -a #{gem_path}`

To cause Visual Studio Code to load the source file containing the entry point for the jekyll_plugin_support gem used in a project, type the following from the Ruby project:

Shell
$ vsopen jekyll_plugin_support

About the Author

I, Mike Slinn, have been working with Ruby for a long time now. Back in 2005, I was the product marketing manager at CodeGear (the company was formerly known as Borland) for their 3rd Rail IDE. 3rd Rail supported Ruby and Ruby on Rails at launch.

In 2006, I co-chaired the Silicon Valley Ruby Conference on behalf of the SD Forum in Silicon Valley. As you can see, I have the t-shirt. I was the sole chairman of the 2007 Silicon Valley Ruby Conference.

Several court cases have come my way over the years in my capacity as a software expert witness. The court cases featured questions about IP misappropriation for Ruby on Rails programs. You can read about my experience as a software expert if that interests you.

I currently enjoy writing Jekyll plugins in Ruby for this website and others, as well as Ruby utilities.

* indicates a required field.

Please select the following to receive Mike Slinn’s newsletter:

You can unsubscribe at any time by clicking the link in the footer of emails.

Mike Slinn uses Mailchimp as his marketing platform. By clicking below to subscribe, you acknowledge that your information will be transferred to Mailchimp for processing. Learn more about Mailchimp’s privacy practices.