microsoft / terminal

The new Windows Terminal and the original Windows console host, all in the same place!
MIT License
95.82k stars 8.33k forks source link

Markdown Notebook Panes #16495

Open heartacker opened 11 months ago

heartacker commented 11 months ago

Pre-requisite: #997

Spec in progress in https://github.com/microsoft/terminal/blob/dev/migrie/s/north-star/doc/specs/NorthStar/Markdown%20Notebooks.md

User Stories

  • A: The user can perform some commandline action (like wt open README.md), which opens a new pane in the Terminal, with the markdown file rendered into that pane.
  • B: Markdown panes have buttons next to code blocks that allow the text of that block to be sent directly to the adjacent terminal as input.
  • C: The user can press different buttons to run some subset of all the commands in the file
    • C.1: Run all the commands in this file
    • C.2: Run all the commands from (the currently selected block) to the end of the file
    • C.1: Run all the commands from (the currently selected block) to the next header. (e.g., run all the commands in this section of the doc.)
  • D: The user can edit the contents of the markdown file directly in the Terminal.
  • E: The Terminal could be configured to automatically open a markdown file when cding to a directory
  • F: The command for opening a markdown file also supports opening files from the web (e.g. directly from GitHub)
  • G: Code blocks in the markdown file are automatically assigned autoincrementing IDs. The user can perform an action (via keybinding, command palette, whatever) to execute a command block from the file, based on it's assigned ID.
  • H: ...

maintainer notes: original OP below the break


Description of the new feature/enhancement

For many developers, especially embedded developers, they would pre-define many text commands and save them in a text file. If WT can split views and open and display text in one view, we can quickly send the text commands to the terminal. I can send lines, send selected blocks, or send the entire content of the file, and preset some shortcuts.

Proposed technical implementation details (optional)

image

zadjii commented 11 months ago

Guys this is totally the notebooks thing I was talking about 😉

But also, there's probably some other useful things we're working on here for "Tasks" - basically, having a big long list of sendInput actions that you can quickly activate - either through the suggestions UI, or maybe even adding a "Tasks" pane.

(we'll probably have more to say after the holidays)

zadjii-msft commented 10 months ago

Okay so, you may be interested in the Suggestions UI and Tasks, which are new in 1.19: Using SendInput Actions in the Suggestions UI

I have Big Plans for these in upcoming releases - some of which is tracked in #13445 (though I think a better thread is floating around here somewhere)

see also:

heartacker commented 10 months ago

no, I know this, and we DO NOT want to config the setting.json, we just want to code in some text file for TeamWorks

so, we want to open the text and the send those command easily, through terminal

zadjii-msft commented 10 months ago

No worries! I've got a lot of related ideas in this space, and untangling them all is sometimes a bit tricky.

You're looking for something more like this?

Yea? A file, with blocks of code that lets you run individual commands, or the whole block?

heartacker commented 10 months ago

This is so innovative. and a little simple txt file for me
We can run the line to terminal where curser focused (with shortcut ) or select some block to run

zadjii-msft commented 10 months ago

Congrats, this gets to be the thread then ☺️

I've been ideating in this space for a long time, just never actually filed a thread for it. I'm gonna co-opt the OP here to add some other notes. Thanks!

heartacker commented 10 months ago

@zadjii-msft here is some demo using vscode.(yes, we can do this with vscode)

  1. text base panel is need indeed (good for teamwork and easy to use)
  2. notebook panel is welcome also (good for guiding)

txt notebook_panel

zadjii-msft commented 8 months ago

reserving for notes for hackathon

9da196da7da7e342698a354a322cfc0265cc9d04: dev/migrie/fhl/notebook-proto-000 was the eldest attempt here, circa March 2023. Notably predates tab tear out. Actual relevant diff was: https://github.com/microsoft/terminal/compare/a04a51bbe4270d65a5a58652772b00fb719261ac...dev/migrie/fhl/notebook-proto-000

2024 spring hack is branched off dev/migrie/fhl/2024-spring-merge-base, https://github.com/microsoft/terminal/compare/dev/migrie/fhl/2024-spring-merge-base...dev/migrie/fhl/2024-inline-notebook

Notes that I have saved locally, but should be persisted elsewhere just in case Notes as I try to make this work There's a lot of in-flight changes to the Terminal, so I'm gonna start off of `sui-panes` + `dev/migrie/til-events-for-all` ## Main workflow: User clicks "Run" on a textblock with a command. We want to send that to the connection. ```c++ buttonPressedHandler(auto&&,auto&&) { Notebook.SendInput(block.Text()); } ``` notebook sends that to the `ControlCore`? Active `TermControl`? Let's start there, by sending it to the active `TermControl` Control does it's thing. Eventually the command ends, and the control raises a `NewPrompt` ### On the `NewPrompt`: * Notebook needs to cork the connection * Remove the connection from the `TermControl`. - Including removing old event handlers * ~~Tell the `TermControl` to stop rendering there.~~ - ~~`TermControl` doesn't actually own the renderer, the `ControlCore` does. So plumb it.~~ - ~~Tell the `Terminal`~~ - The TermControl can totally just keep rendering. That's fine. * Create a new `TermControl`, - Start by instantiating a new `ExistingControlData` - Create a new `BlockRenderData`. This renderdata starts at the current,new mark, and doesn't have a bottom set - the existing root `Terminal` - the existing connection - Pass that to a new ControlInteractivity/ControlCore - Who grabs the `RenderData` out of that existing control data and uses it to create a new `Renderer` - Add that content (ControlInteractivity) to a new TermControl - attach the connection to it - mark the new control as the active one. ### On a `CommandStarted`: This is when the control actually needs to be rendered. Raise some event that notebook can bubble to mark it as `Visible` ### Some interfaces ```csharp class Notebook { Notebook(ITerminalConnection connection, Settings...); } ``` ```c++ class Notebook { TermControl[] controls; TermControl active; ITerminalConnection connection; shared_ptr terminal; Notebook(ITerminalConnection connection, Settings...); // Initialize the terminal, the NotebookRenderData, and the first TermControl void NewPromptHandler() } class NotebookRenderData : IRenderData { } interface IControlData { IRenderData* renderData; Terminal* terminal; ITerminalConnection connection; } struct Control.ExistingControlData : IControlData { IRenderData* renderData; Terminal* terminal; ITerminalConnection connection; } ``` The `IRenderData` for a control is just the `Terminal` itself. `TextBuffer` is created with a reference to a `Renderer`. Yike. In the `ControlCore` ctor is where we construct the `Renderer` and pass in the `Terminal` as the `IRenderData` ~~`Terminal` already knows how to be a `IRenderData` so we can just modify it's implementation to also work in block mode. NO NO NO there's only one Terminal. It needs to implement a second IBlockRenderData interface, and have the control nah fuck~~ ```c++ ControlCore::ControlCore(ExistingControlData dataFromNotebook, Settings...) { _terminal = dataFromNotebook.terminal; _renderer = make_unique(renderSettings, dataFromNotebook.renderData, // IRenderData nullptr, // pEngine 0, // cEngines std::move(renderThread)); } ``` The notebook holds the `Terminal`. It holds a bunch of controls&cores. So there's one Renderer for each control. Each renderer is given a NotebookRenderData that the Notebook owns and instantiates for each control. ## At creation We instantiate a new `Notebook`, with the given connection and settings. - It's going to create a `Terminal`, - Passing in to that Terminal, it'll pass it's own renderdata? Terminal already implements IRenderData. And on `Terminal::Create()`, Terminal recieves a `Renderer&`. That's annoying. We - And eventually, a first `TermControl`. ## Todo list * [x] Convert the `Renderer&` in `TextBuffer` and `AdaptDispatch` (et. al) to be a `Renderer*`, since references can't be reassigned. * [x] `Terminal` needs a ChangeRenderer method that takes a `Renderer*` and updates the buffer et al. * [x] Create a `BlockRenderData` class, (In `TerminalCore` project, why not) * [x] implements `IRenderData`, * [x] Takes a `Terminal*` as a param * [x] Originally, just implement as a passthrough on all the TerminalRenderData methods * [x] Change ControlCore to have a public non-projected ctor which takes a `IControlData` and settings, and initialize the `_terminal` from that if given. * [x] Create a `Notebook` class in `Terminal.Control`. * [x] Just stick a pair of TermControls into the notebook. At this point, I was able to stick the pair of TermControls from the notebook into the `MyPage` of the scratch project. * [x] De-dupe the input. - I think there's two OUTPUT handlers registered somewhere. * [ ] Update all bocks when relevant * [ ] Start making more blocks for each command

2024-march-14 lunch screenshot: image

Updates archive _2024-march-13 lunch screenshot_: ![fhl-notebooks-with-progress](https://github.com/microsoft/terminal/assets/18356694/3bd160f1-4c46-4706-a5ad-a27f201a82bc) _2024-march-12 EoD screenshot_: ![image](https://github.com/microsoft/terminal/assets/18356694/9fa11089-7f4f-4983-b211-ac4bf195b40a) _2024-march-11 EoD screenshot_: ![image](https://github.com/microsoft/terminal/assets/18356694/0c1071c1-499d-4dd9-a30a-bced9f163c24) _2024-march-11 lunch screenshot_: ![image](https://github.com/microsoft/terminal/assets/18356694/a5ffd870-2385-4d5a-a722-6d92a8fbcc95) _2024-march-08 screenshot_: ![image](https://github.com/microsoft/terminal/assets/18356694/8ad7fd1a-3bab-418e-bb73-33f8b4351b67) These two blocks both share a single `Connection` and `Terminal`. They have separate `ControlCore` & `ControlInteractivity` & `TermControl`'s. Only the last one actually gets updates to its viewport, we should fix that.

Conclusions

Overall, project was a huge success. Clearly, it's possible to have Terminal notebooks that have a single hidden connection & terminal core, and then have a markdown frontend for that notebook, with each block of output rendered separately.

However, at this point, one should probably ask: why the heck isn't this just .ipynb's? Especially with the existence of:

Couldn't the Terminal just be a kernel for that? There's not really a reason why not, right? And if we want to do that, then we really don't need... any... of what was written here. I should have probably done more research first.


There's probably also still value in the side-by-side UX. Probably.

zadjii-msft commented 8 months ago

I'm gonna leave the above comment for the "inline notebooks" investigation that eventually petered out, and use this one for side-by-side markdown in the Terminal

Branch map:

2024-march-15 end of hackathon: fhl-markdown-open-demo

Updates archive _2024-march-14 EoD screenshot_: ![image](https://github.com/microsoft/terminal/assets/18356694/204f83af-5ea1-45ba-8b70-0e5939eb1ecb)
heartacker commented 8 months ago

Could you please provide a another text base panel, not only markdown panel?

zadjii-msft commented 8 months ago

Sure, why not. Rendering plaintext is easy comparatively to rendering markdown in WinUI 😜

fhl-markdown-open-text-file

heartacker commented 8 months ago

Sure, why not. Rendering plaintext is easy comparatively to rendering markdown in WinUI 😜

fhl-markdown-open-text-file

thank ,now i just need a short cut to send the line command without text_selected ,or selected_text command ,

after that ,we don't need copy->paste->commit line