Skip to content

Conversation

@davidanthoff
Copy link
Member

@davidanthoff davidanthoff commented Feb 18, 2020

Fixes #516.

@pfitzseb told me how we can have a better hook into the REPL, so this PR brings this feature back.

And it is improved :) Better UI for vars, a button to open things like tables in the grid viewer or plots in the plot pane directly from the workspace.

Open issues:

  • Add support for hierarchical drill down into composite, array and dict variables EDIT: deferred
  • Decide whether we should for example show functions defined? EDIT: for now lets just show them
  • Should we have our own Julia explorer, instead of putting this into the file thingy?
  • Don't show @run and @enter in the var list
  • Make sure internal_vscodedisplay works with anything we throw at it (in particular vectors and matrices) EDIT: Solved in Rearrange code and add support for vector and matrix to grid #1258.

@davidanthoff davidanthoff self-assigned this Feb 18, 2020
@davidanthoff davidanthoff added this to the v0.15.0 milestone Feb 18, 2020
@zhopan77
Copy link

Glad to see this feature is already being developed! This is one of the top 3 in my wish list to get our colleague to adopt Julia + VSCode as standard development environment.

FY the other two being intellisense for local module on LOAD_PATH and loaded with "using" or "import"; and GUI for profiler. All these 3 features are currently supported by Juno, but we prefer VSCode's overall performance.

@davidanthoff davidanthoff modified the milestones: v0.15.x, Backlog May 24, 2020
@davidanthoff
Copy link
Member Author

@julia-vscode/core I'm tempted to merge an initial version of this without tree drill-down, and then add that in a later version? If we were to go with that, this is almost ready to go.

We could for example ship a v0.16 that includes the inline eval results, the module selector and this PR, and all relatively soon?

@pfitzseb
Copy link
Member

Yeah, let's do that. The main difficulty with the tree drill functionality is that it needs to be lazy to be useful (in case of circular refs and really big objects, both of which happen all the time). Juno in theory has the code for that, but in practice it's buggy and might mess with the GC at times, so we should be very careful about the implementation.

@davidanthoff
Copy link
Member Author

Ha, I had hoped you had a good way to handle the lazy thing :) I've been thinking how to do this, and always ended up at "that is actually quite tricky"... We should probably look at the debug adapter protocol implementation again, that seems fairly robust and we could probably mimic that. But yes, lets do that later.

@davidanthoff davidanthoff marked this pull request as ready for review May 30, 2020 17:53
@davidanthoff davidanthoff modified the milestones: Backlog, Next extension minor release May 30, 2020
Comment on lines 28 to 30
x==Main.vscodedisplay && continue
n==Symbol("@run") && continue
n==Symbol("@enter") && continue
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why we don't wrap those three into _vscodeserver ? export @run, @enter; using _vscodeserver won't work ?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yep, good idea! That won't change the need to filter them out here, right?

Should we do this in a separate PR?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If we wrap them in _vscodeserver, then these condition check won't be needed since you get those names only from Main

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

xref: #1228

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That raises a good point, actually -- we should probably have a way to switch modules (or follow the editor module).

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yeah, while I think module switching can be done in another follow up PR.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We should probably have a tree drill down for modules in the workspace, right? Definitely a new PR, though :)

I'll do the rearrangements that @aviatesk suggested in a new PR once this one here is merged.

@davidanthoff davidanthoff marked this pull request as draft June 2, 2020 18:56
@davidanthoff davidanthoff marked this pull request as ready for review June 2, 2020 19:18
Copy link
Member

@pfitzseb pfitzseb left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good to me. Left a few comments inline.


@async begin

@async try
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What's the point of this? The REPL connection is effectively dead after the catch anyways, no?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There is at least an error message shown in the REPL, otherwise the error just silently disappears. What we should really do is put a crash report into the catch block, I'll do that in a new PR once this one is merged (it requires a few more things).


# Replace all top level assignments with a global top level assignment
# so that they happen, even though the code now runs inside a
# try ... finally block
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

FWIW, Juno doesn't bother with all of this and instead does something like

  main_mode.on_done = REPL.respond(Base.active_repl, main_mode; pass_empty = false) do line
    if !isempty(line)
      quote
        $evalrepl($mod, $line)
      end
    end
  end
function evalrepl(mod, line)
  try
    errored = false
    JSONRPC.send_notification(conn_endpoint, "repl/starteval", nothing)
    with_logger(JunoProgressLogger()) do
      try
         line = Meta.parse(line)
      catch err
        errored = true
        display_parse_error(stderr, err)
      end
      errored && return nothing
      try
        repleval(mod, line)
      catch err
        display_error(stderr, err, stacktrace(catch_backtrace()))
      end
    end
    errored ? nothing : ans
  catch err
    # This is for internal errors only.
    display_error(stderr, err, stacktrace(catch_backtrace()))
  finally
    JSONRPC.send_notification(conn_endpoint, "repl/finisheval", nothing)
  end
end

I'm not sure which approach I like better though.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm also unsure :) Should we merge as is for now, and then we can revisit later?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sure.

let treeItem = new vscode.TreeItem(`${node.name}:`)
treeItem.description = node.value;
treeItem.tooltip = node.type;
treeItem.contextValue = 'globalvariable';
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we make this depend on whether it's actually possible for us to display them in VSCode? That way the button would only show up for tables and plots and stuff?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not really, the problem are tables: in the Queryverse world you can have a query where you can't tell whether something is a table or not until you try to iterate the rows for it, i.e. until you actually try to materialize the results of the query. So that pretty fundamentally prevents us from telling with certainty whether we should show the button or not.

We could, though, narrow things down a lot: the case I described above is rare, and in very many cases we should actually be able to tell whether we can show the value or not.

I've put this onto my list for another follow up PR, ok?

@aviatesk
Copy link
Member

aviatesk commented Jun 3, 2020

So one thing I think we need to address before merging would be how to handle "big" objects.
Say, if we execute julia> collect(1:1000000) then vsc will kinda freeze on low spec PC.
I guess we might need to use strlimit or something like IOContext(:limit => true) here

@aviatesk
Copy link
Member

aviatesk commented Jun 3, 2020

So one thing I think we need to address before merging would be how to handle "big" objects.

well, I think a fairly simple solution would be enough for this PR. Implementing more complicated and fancier solution like lazy display as in Juno shouldn't hold this PR imho.

n_as_string=="@enter" && continue
startswith(n_as_string, "#") && continue
t = typeof(x)
value_as_string = Base.invokelatest(repr, x)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This should probably be show, no? Also would be best to stringlimit this, as @aviatesk mentioned below.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Or maybe just wrap

str = filter(isvalid, strlimit(sprint(io -> Base.invokelatest(Base.display_error, IOContext(io, :limit => true, :color => false, :displaysize => (100, 64)), err.err, err.bt)), 10_000))

into a function and reuse that.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is not related to this PR, but strlimit already handles isvalid character case, so we don't need outer isvalid filtering, right ?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, I just mindlessly copy-pasted code there ;)

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I had used repr here because that is what we use for the debugger. But I guess the situation here is different: for the debugger we ideally want the ability to round-trip things (because users can modify the value of a var in the tree view that shows vars), whereas here that is not a concern. Although: we could of course in the future add an ability to change variable values in the workspace view? In any case, I've changed it to show for now, we can iterate in future PRs.


JSONRPC.send_success_response(conn_endpoint, msg, [Dict{String,String}("name"=>i.name, "type"=>i.type, "value"=>i.value) for i in vars])
elseif msg["method"] == "repl/showingrid"
var = Core.eval(Main, Meta.parse(msg["params"]))
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This should probably be written as

            var = try
                getfield(Main, Symbol(msg["params"]))
            catch err
                Base.display_error(err, catch_backtrace())
                return
            end

            try
                Base.invokelatest(internal_vscodedisplay, var)
            catch err
                Base.display_error(err, catch_backtrace())
            end

or something similar.

@aviatesk aviatesk mentioned this pull request Jun 3, 2020
2 tasks
@davidanthoff
Copy link
Member Author

Alright, I think I addressed the most urgent comments.

In general, what I quite often do with feedback on these large PRs is that for things that are super critical, I make a note and then open new smaller PRs right after this PR here has been merged. I generally find that an easier workflow: the less I change in response to your comments here, the less churn we have and the faster we can merge this PR here :) Hope that is ok, I will do those (small) follow up PRs before we ship.

@pfitzseb
Copy link
Member

pfitzseb commented Jun 3, 2020

Yup, sounds good.

@davidanthoff davidanthoff merged commit 6682718 into master Jun 3, 2020
@davidanthoff davidanthoff deleted the workspace branch June 3, 2020 17:43
davidanthoff added a commit that referenced this pull request Jun 4, 2020
@tj10ai
Copy link

tj10ai commented Aug 25, 2020

What is the status of the debugger for VScode for Julia? It is working great except my debug windows for variables, stack... are blank when I run debug on Julia code. Is this because of a bug or it is me? Here is what I have installed:

VScode_Julia_Config_ _Debug_No_Info
Version: 1.48.1 (system setup)
Commit: 3dd905126b34dcd4de81fa624eb3a8cbe7485f13
Date: 2020-08-19T17:12:13.244Z
Electron: 7.3.2
Chrome: 78.0.3904.130
Node.js: 12.8.1
V8: 7.8.279.23-electron.0
OS: Windows_NT x64 10.0.18363

In the attachment/screenshot you can see that I have not made any changes to the config - is this part of my problem getting this to work properly?

@davidanthoff
Copy link
Member Author

@tj10ai can you open a new issue for distinct problems? This was a PR for the workspace view.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Add a Workspace / Variables / Data Explorer

6 participants