crystal-lang-tools/vscode-crystal-lang

New release?

jwoertink opened this issue ยท 20 comments

The last release 0.8.4 was added on 2022-1-27, 11:51:14. Since that release was tagged, there's been several updates made (18 commits), including a few (#165, #173) PRs that may be ready to go.

I've never released a plugin for VSCode, so I'm not sure how involved it is, but I would like to at least get the conversation started on what all it might take to get a new release out. Or maybe a beta release to test out all of these changes?

Thank you!

I've been working on testing the current code to make sure everything works across the various platforms before release (linux, windows, macos) and to debug issues people have ran into. I've conversed with @bcardiff about this and we should be able to do a release when everything's ready, particularly when #173 is merged.

Awesome! That's great to hear ๐Ÿš€ Thanks for the update โค๏ธ

Thank you as well for reaching out! I'll use this issue for keeping track of the upcoming release.

As part of helping me test this for release, I put together a list of features, short descriptions, how they work at a high level, and known current issues. Eventually I want to work this into the wiki, but for now it's a good starting point for what to test to ensure everything works. If anyone is up to help assist in testing this before release, I've attached a development version of the current changes on #173.

crystal-lang-0.8.5.vsix.zip

Features

  • Syntax highlighting

    • Description
      • Highlights Crystal source code in '*.cr' files as well as in Markdown code blocks.
      • Also highlights template files such as ECR and Slang.
    • How it works
      • A series of regex's in a TextMate grammar that match language constructs.
    • Potential problems
      • Heredoc's are currently broken
  • Auto indentation

    • Description
      • Auto-indents as code is typed into the editor based on the code being typed.
    • How it works
      • Two regex's in the main file which determine when to indent and when to de-indent
    • Potential problems
      • include is currently mistaken as in and is de-indented when it is not supposed to
  • Snippets

    • Description
      • A series of small code completions for common use cases, such as begin expanding to include a rescue and an end statement
    • How it works
      • A JSON file for completions for Crystal, ECR, and Slang, which have a "prefix" to look for, and a "body" to replace it with
      • Replacement happens immediately
    • Potential problems
      • May come across situations where a snippet is activated where the developer did not intend for it to happen, leading to frustration and a worse experience
      • Some of the snippets don't work, such as ECR ones with symbol prefixes
  • Formatting

    • Description
      • A vscode command that will automatically format your code using the Crystal formatter built into the compiler itself
      • Can also format automatically on save
    • How it works
      • The code from the current file is copied and sent through the compiler's formatting tool, returning the formatted code
      • Is very fast as it only operates on one file
    • Potential problems
      • If the code is not proper source (some bug or issue), the formatter will not do anything or return an error
  • Problems finder

    • Description
      • Automatically compiles the source code when a file is open or saved to find issues without needing to run the compiler manually
    • How it works
      • Grabs the source code and tries building it. If it runs into an issue, the issue is reported to a VSCode diagnostic collection
    • Potential problems
      • Constantly running Crystal in the background can be slow and use a lot of resources
      • Speed depends on how much the compiler has to run before finding issues
  • Document Symbols

    • Description
      • Allows for easier code navigation through breadcrumbs at the top of the file, as well as being viewable via a keyboard shortcut
    • How it works
      • A file is manually parsed using regex's line by line, creating symbols where they're found
    • Potential problems
      • Very slow and error prone
      • Will not work if mainFile is not set
      • Does not seem to work in general
  • Peek and go to definition

    • Description
      • Allows for quickly jumping to the definition of a method
    • How it works
      • Spawns the implementations tool built into the Crystal compiler to find the locations of definitions
    • Potential problems
      • Very slow as it calls the compiler every time
      • Sometimes doesn't do anything
      • Will not work if mainFile is not set
  • Show symbol information on hover

    • Description
      • Will provide information on a piece of code when hovering the mouse
    • How it works
      • When hovering, the place in code is captured and passed off to the Crystal compiler's context tool, which returns the information from it
    • Potential problems
      • Sometimes doesn't provide much information, especially for non-stdlib stuff such as methods within the same codebase
  • Method completion for Literals and Symbols

    • Description
      • Provides code completions, allowing the developer to know what methods are available on an object
    • How it works
      • Calls the Crystal context tool and parses the output
    • Potential problems
      • Doesn't provide completions for several objects, but does for File and Dir objects
  • Tasks

    • Description
      • Allow a quick way of executing various tasks in VSCode projects
    • How it works
      • Calls the task in the background when executed, output shown in a temporary terminal
    • Potential problems

Platform Support Goal (at minimum)

  • Linux
    • Arch Linux
    • Latest Ubuntu
    • Fedora
  • MacOS
    • Intel
    • Apple Silicon
  • Windows
    • 10 Native
    • 10 WSL 2
    • 11
  • Web
    • GitHub Codespaces

nice! I'm down to test this. How do I install that zip? Unpack it, and move it to some vscode directory? Looks like I have a ~/.vscode/extensions/ directory... Great work on this!

Thank you! To install it, you just need to extract it and install it from within vscode: https://code.visualstudio.com/docs/editor/extension-marketplace#_install-from-a-vsix

Make sure to reload the window after installing to ensure you're running the right version.

Ok, seeing a few things here... Would you like me to list them out in this thread? or just open up new issues?

We can start with a comment here with a basic overview of the issues you're seeing, including OS information and stuff. From there we can create issues.

When I save one of my models, sometimes it'll randomly say that the class it inherits from doesn't exist:
image
If I open up that BaseModel file, then go back to my Emote model, the error goes away.
Seems it also happens with included modules
image
image

โฏ neofetch
             /////////////                jeremy@pop-os 
         /////////////////////            ------------- 
      ///////*767////////////////         OS: Pop!_OS 22.04 LTS x86_64 
    //////7676767676*//////////////       Host: Thelio Mira thelio-mira-r1 
   /////76767//7676767//////////////      Kernel: 6.4.6-76060406-generic 
  /////767676///*76767///////////////     Uptime: 3 days, 1 hour, 10 mins 
 ///////767676///76767.///7676*///////    Packages: 2912 (dpkg), 56 (flatpak), 20 (snap) 
/////////767676//76767///767676////////   Shell: bash 5.1.16 
//////////76767676767////76767/////////   Resolution: 1920x1080, 3840x2160 
///////////76767676//////7676//////////   DE: GNOME 42.5 
////////////,7676,///////767///////////   WM: Mutter 
/////////////*7676///////76////////////   WM Theme: Pop 
///////////////7676////////////////////   Theme: Pop [GTK2/3] 
 ///////////////7676///767////////////    Icons: pop-os-branding [GTK2/3] 
  //////////////////////'////////////     Terminal: gnome-terminal 
   //////.7676767676767676767,//////      CPU: AMD Ryzen 5 5600X (12) @ 3.700GHz 
    /////767676767676767676767/////       GPU: NVIDIA GeForce RTX 3070 Ti 
      ///////////////////////////         Memory: 10001MiB / 64202MiB 
         /////////////////////
             /////////////                                        
                                                                  
Version: 1.81.0
Commit: 6445d93c81ebe42c4cbd7a60712e0b17d9463e97
Date: 2023-08-02T12:36:11.334Z
Electron: 22.3.18
ElectronBuildId: 22689846
Chromium: 108.0.5359.215
Node.js: 16.17.1
V8: 10.8.168.25-electron.0
OS: Linux x64 6.4.6-76060406-generic snap

Do you have 'mainFile' set in your settings for this workspace? It's unfortunately a requirement for a lot of functionality provided by 'crystal tool', and I do think we should either pull it from 'targets' in shards.yml or make it more prominent it needs to be set.

I don't have that field set.
image

Since the main file changes per project, what would be the best way to set this? For example, on each Lucky project, the main file is the name of the project, so if my project is named foo, then my main file would be src/foo.cr. I could use src/start_server.cr, but then when I'm not in a Lucky project, that wouldn't exist.

Thinking about it though, it would make things easier if we adopted a single src/main.cr for every project always ๐Ÿ˜‚ Though, crystal init app test generates a src/test.cr file for the main ๐Ÿค”

Ok, adding that main does seem to solve that issue ๐Ÿ‘

Maybe we can default to src/project_name.cr if mainFile isn't set? Also you can have vscode settings be per project afaik, and it'll save it in a '.vscode/settings.json' in the project itself, so you don't need to set it globally for all projects. The documentation/error handling for this could be better.

Ok, I think I have one more thing... I've tanked my machine twice today by fulling running out of (64GB) memory...

When I type a lot of comments, the system seems to just come to a crawl then crash. As in, I'm just commenting on code, and then it all goes bonkers

image

Oh god I'm sorry! I have no idea what could've caused that, maybe too many instances of the compiler running? Honestly, I'm almost to the point of leaving the current version as-is and moving over to put my efforts into the rewrite. This was really only supposed to be small fixes to make things easier and be a hold-over until the rewrite was stable but now I'm unsure if it's worth it.

maybe too many instances of the compiler running

Yeah, I'm pretty sure this is what it was. I was able to run top after and saw like 30 crystal compilers that seemed to be doing stuff. Once VSCode was closed, and I waited a few minutes, everything returned to normal. Maybe it was just trying to run a new one on each keystroke or something? We actually had a similar issue in Lucky a while back. There's a built-in watcher and each time you'd save a file, it kicks off a new crystal compiler to recompile the app. The issue was if you made several changes and saved several files, it would kick off a new one for each file saved.

To fix that, we had to basically store the current process, and if a new save comes in, then we just stop that one and do a new one.

https://github.com/luckyframework/lucky/blob/d60191eb057230f8eb2cd4d446ad791742284613/tasks/watch.cr#L159-L198

what would be the best way to set this?

Using the shards.yml targets values if they exists seems like a good default. But I am not sure how to deal when there are multiple.

Having an option to use specs as main file (that will require **/*_spec.cr on the fly) might be a good checkbox/option to have since that is neither a target in shards.tml nor is usually the case of a single file that includes all specs.

Just added a commit that treats specs as their own main files, ignoring the mainFile if set, when executing implementations/etc. I also reverted enabling completions / implementations / hover as I believe one of them was causing the memory issue and I haven't had the time to investigate which.

y8 commented

Thanks for the build!

I'm having issues with build task for a project where shards.yml have more than one target.

For example, I have a list of targets:

targets:
  agent:
    main: src/app/agent.cr
  beacon:
    main: src/app/beacon.cr
  server:
    main: src/app/server.cr    

And build task:

{
  "version": "2.0.0",
  "tasks": [
    {
      "type": "crystal",
      "command": "run",
      "file": "src/app/beacon.cr",
      "label": "Crystal: run - src/app/beacon.cr",
      "group": {
        "kind": "build",
        "isDefault": true
      }
    }
  ]
}

When I'm trying to launch this task I'm getting:

Error: The crystal task detection didn't contribute a task for the following configuration:
{
    "type": "crystal",
    "command": "run",
    "file": "src/app/beacon.cr",
    "label": "Crystal: run - src/app/beacon.cr",
    "group": {
        "kind": "build",
        "isDefault": true
    }
}
The task will be ignored.

It seems like task accept only first target, failing to launch any others.

Also it doesn't work with arbitrary files, for example this task that that supposed to run currently open file won't work either:

{
  "version": "2.0.0",
  "tasks": [
    {
      "type": "crystal",
      "command": "run",
      "file": "${file}",
      "problemMatcher": [],
      "label": "Crystal: run current file",
      "group": {
        "kind": "build",
        "isDefault": true
      }
    }
  ]
}

Maybe I'm missing something in configuration?

@y8 thank you for the writeup, I'm going to create a separate issue for this