Magma is a NeoVim plugin for running code interactively with Jupyter.

Related tags

CLI Tools magma-nvim
Overview

Magma

Magma is a NeoVim plugin for running code interactively with Jupyter.

Requirements

  • NeoVim 0.5+
  • Python 3.8+
  • Required Python packages:
    • pynvim (for the Remote Plugin API)
    • jupyter_client (for interacting with Jupyter)
    • ueberzug (for displaying images)
    • Pillow (also for displaying images, should be installed with ueberzug)
    • cairosvg (for displaying SVG images)
    • pnglatex (for displaying TeX formulas)
    • plotly and kaleido (for displaying Plotly figures)

You can do a :checkhealth to see if you are ready to go.

Note: Python packages which are used only for the display of some specific kind of output are only imported when that output actually appears.

Installation

Use your favourite package/plugin manager.

If you use packer.nvim,

use { 'dccsillag/magma-nvim', run = ':UpdateRemotePlugins' }

If you use vim-plug,

Plug 'dccsillag/magma-nvim', { 'do': ':UpdateRemotePlugins' }

Note that you will still need to configure keymappings -- see Keybindings.

Suggested settings

If you want a quickstart, these are the author's suggestions of mappings and options (beware of potential conflicts of these mappings with your own!):

nnoremap  r  :MagmaEvaluateOperator
nnoremap        rr :MagmaEvaluateLine
xnoremap        r  :MagmaEvaluateVisual
nnoremap        rc :MagmaReevaluateCell
nnoremap        rd :MagmaDelete
nnoremap        ro :MagmaShowOutput

let g:magma_automatically_open_output = v:false

Note: Key mappings are not defined by default because of potential conflicts -- the user should decide which keys they want to use (if at all).

Note: The options that are altered here don't have these as their default values in order to provide a simpler (albeit perhaps a bit more inconvenient) UI for someone who just added the plugin without properly reading the README.

Usage

The plugin provides a bunch of commands to enable interaction. It is recommended to map most of them to keys, as explained in Keybindings. However, this section will refer to the commands by their names (so as to not depend on some specific mappings).

Interface

When you execute some code, it will create a cell. You can recognize a cell because it will be highlighted when your cursor is in it.

A cell is delimited using two extmarks (see :help api-extended-marks), so it will adjust to you editing the text within it.

When your cursor is in a cell (i.e., you have an active cell), a floating window may be shown below the cell, reporting output. This is the display window, or output window. (To see more about whether a window is shown or not, see :MagmaShowOutput and g:magma_automatically_open_output). When you cursor is not in any cell, no cell is active.

Also, the active cell is searched for from newest to oldest. That means that you can have a cell within another cell, and if the one within is newer, then that one will be selected. (Same goes for merely overlapping cells).

The output window has a header, containing the execution count and execution state (i.e., whether the cell is waiting to be run, running, has finished successfully or has finished with an error). Below the header are shown the outputs.

Jupyter provides a rich set of outputs. To see what we can currently handle, see Output Chunks.

Commands

MagmaInit

This command initializes a runtime for the current buffer.

It can take a single argument, the Jupyter kernel's name. For example,

:MagmaInit python3

will initialize the current buffer with a python3 kernel.

It can also be called with no arguments, as such:

:MagmaInit

This will prompt you for which kernel you want to launch (from the list of available kernels).

MagmaDeinit

This command deinitializes the current buffer's runtime and magma instance.

:MagmaDeinit

Note You don't need to run this, as deinitialization will happen automatically upon closing Vim or the buffer being unloaded. This command exists in case you just want to make Magma stop running.

MagmaEvaluateLine

Evaluate the current line.

Example usage:

:MagmaEvaluateLine

MagmaEvaluateVisual

Evaluate the selected text.

Example usage (after having selected some text):

:MagmaEvaluateVisual

MagmaEvaluateOperator

Evaluate the text given by some operator.

This won't do much outside of an mapping. Example usage:

nnoremap  r nvim_exec('MagmaEvaluateOperator', v:true)

Upon using this mapping, you will enter operator mode, with which you will be able to select text you want to execute. You can, of course, hit ESC to cancel, as usual with operator mode.

MagmaReevaluateCell

Reevaluate the currently selected cell.

:MagmaReevaluateCell

MagmaDelete

Delete the currently selected cell. (If there is no selected cell, do nothing.)

Example usage:

:MagmaDelete

MagmaShowOutput

This only makes sense when you have g:magma_automatically_open_output = v:false. See Customization.

Running this command with some active cell will open the output window.

Example usage:

:MagmaShowOutput

MagmaSave

Save the current cells and evaluated outputs into a JSON file, which can then be loaded back with :MagmaLoad.

It has two forms; first, receiving a parameter, specifying where to save to:

:MagmaSave file_to_save.json

If that parameter is omitted, then one will be automatically generated using the g:magma_save_path option.

:MagmaSave

MagmaLoad

Load the cells and evaluated outputs stored in a given JSON file, which should have been generated with :MagmaSave.

Like MagmaSave, It has two forms; first, receiving a parameter, specifying where to save to:

:MagmaLoad file_to_load.json

If that parameter is omitted, then one will be automatically generated using the g:magma_save_path option.

Keybindings

It is recommended to map all the evaluate commands to the same mapping (in different modes). For example, if we wanted to bind evaluation to r:

nnoremap  r  nvim_exec('MagmaEvaluateOperator', v:true)
nnoremap        rr :MagmaEvaluateLine
xnoremap        r  :MagmaEvaluateVisual
nnoremap        rc :MagmaReevaluateCell

This way, r will behave just like standard keys such as y and d.

You can, of course, also map other commands:

nnoremap  rd :MagmaDelete
nnoremap  ro :MagmaShowOutput

Customization

Customization is done via variables.

g:magma_automatically_open_output

Defaults to v:true.

If this is true, then whenever you have an active cell its output window will be automatically shown.

If this is false, then the output window will only be automatically shown when you've just evaluated the code. So, if you take your cursor out of the cell, and then come back, the output window won't be opened (but the cell will be highlighted). This means that there will be nothing covering your code. You can then open the output window at will using :MagmaShowOutput.

g:magma_cell_highlight_group

Defaults to "CursorLine".

The highlight group to be used for highlighting cells.

g:magma_save_path

Defaults to stdpath("data") .. "/magma".

Where to save/load with :MagmaSave and :MagmaLoad (with no parameters).

The generated file is placed in this directory, with the filename itself being the buffer's name, with % replaced by %% and / replaced by %, and postfixed with the extension .json.

[DEBUG] g:magma_show_mimetype_debug

Defaults to v:false.

If this is true, then before any non-iostream output chunk, Magma shows the mimetypes it received for it.

This is meant for debugging and adding new mimetypes.

Extras

Output Chunks

In the Jupyter protocol, most output-related messages provide a dictionary of mimetypes which can be used to display the data. Theoretically, a text/plain field (i.e., plain text) is always present, so we (theoretically) always have that fallback.

Here is a list of the currently handled mimetypes:

  • text/plain: Plain text. Shown as text in the output window's buffer.
  • image/png: A PNG image. Shown with Ueberzug.
  • image/svg+xml: A SVG image. Rendered into a PNG with CairoSVG and shown with Ueberzug.
  • application/vnd.plotly.v1+json: A Plotly figure. Rendered into a PNG with Plotly + Kaleido and shown with Ueberzug.
  • text/latex: A LaTeX formula. Rendered into a PNG with pnglatex and shown with Ueberzug.

This already provides quite a bit of basic functionality. As development continues, more mimetypes will be added.

Notifications

We use the vim.notify API. This means that you can use plugins such as rcarriga/nvim-notify for pretty notifications.

License

This code is licensed under the GPLv3 (due to Ueberzug using it).

Comments
  • Bug: error when trying to show image

    Bug: error when trying to show image

    For the following code:

    import numpy as np                                                
    import matplotlib.pyplot as plt                                   
                                                                                                                    
    x = np.random.rand(10000)                                         
    plt.hist(x)                                                    
    

    I get the following error:

    Error detected while processing function remote#define#request:                                                                                                       
    line    2:                                                                                                                                                            
    Error invoking '/home/tzachar/.local/share/nvim/site/pack/packer/opt/magma-nvim/rplugin/python3/magma.py:autocmd:CursorMoved:*' on channel 7 (python3-rplugin-host):  
    error caught in request handler '/home/tzachar/.local/share/nvim/site/pack/packer/opt/magma-nvim/rplugin/python3/magma.py:autocmd:CursorMoved:* []':                  
    Traceback (most recent call last):                                                                                                                                    
      File "/home/tzachar/.local/share/nvim/site/pack/packer/opt/magma-nvim/rplugin/python3/magma.py", line 47, in inner                                                  
        func(self, *args, **kwargs)                                                                                                                                       
      File "/home/tzachar/.local/share/nvim/site/pack/packer/opt/magma-nvim/rplugin/python3/magma.py", line 965, in autocmd_cursormoved                                   
        self._update_interface()                                                                                                                                          
      File "/home/tzachar/.local/share/nvim/site/pack/packer/opt/magma-nvim/rplugin/python3/magma.py", line 824, in _update_interface                                     
        magma.update_interface()                                                                                                                                          
      File "/home/tzachar/.local/share/nvim/site/pack/packer/opt/magma-nvim/rplugin/python3/magma.py", line 694, in update_interface                                      
        self._show_selected(self.selected_cell)                                                                                                                           
      File "/home/tzachar/.local/share/nvim/site/pack/packer/opt/magma-nvim/rplugin/python3/magma.py", line 737, in _show_selected                                        
        self._show_outputs(self.outputs[span], span.end)                                                                                                                  
      File "/home/tzachar/.local/share/nvim/site/pack/packer/opt/magma-nvim/rplugin/python3/magma.py", line 611, in _show_outputs                                         
        chunktext = chunk.place(lineno, shape, self.canvas)                                                                                                               
      File "/home/tzachar/.local/share/nvim/site/pack/packer/opt/magma-nvim/rplugin/python3/magma.py", line 264, in place                                                 
        if ((self.img_width/xpixels)/(self.img_height/ypixels))*max_nlines <= w:                                                                                          
    ZeroDivisionError: division by zero                                                                                                 
    
    bug 
    opened by tzachar 30
  • bug: Some error related to switching/opening buffers

    bug: Some error related to switching/opening buffers

    error caught in async handler '/home/amedhi/.local/share/nvim/site/pack/packer/opt/magma-nvim/rplugin/pyth
    on3/magma.py:autocmd:BufUnload:* []'                                                                      
    Traceback (most recent call last):                                                                        
      File "/home/amedhi/.local/share/nvim/site/pack/packer/opt/magma-nvim/rplugin/python3/magma.py", line 47,
     in inner                                                                                                 
        func(self, *args, **kwargs)                                                                           
      File "/home/amedhi/.local/share/nvim/site/pack/packer/opt/magma-nvim/rplugin/python3/magma.py", line 990
    , in autocmd_bufunload                                                                                    
        magma = self.buffers.get(int(self.nvim.funcs.expand('<abuf>')))                                       
    ValueError: invalid literal for int() with base 10: ''                        
    

    I can't seem to nail down exactly when it happens but one reliable way is to hit <leader>, wait for which-key.nvim to show up then hit <ESC>

    I see it is something to do with the BufUnload autocommand so I guess it's to do with leaving the buffer

    Also doing a LSP search for references leads to this happening many times

    bug 
    opened by IndianBoy42 16
  • [Bug] Cannot start MagmaInit

    [Bug] Cannot start MagmaInit

    Hello, this is not a bug but I cannot use the plugin at all. Installation went smoothly and :checkhealth appears fine but I simply cannot fire the plugin using :MagmaInit, it is like the plugin was not installed. I am probably doing something very stupid

    :checkhealth image

    :version image

    ~/.init.vim is empty image

    Describe the bug E492: Not an editor command: Magma

    To Reproduce Simply type :MagmaInit

    Screenshots image

    Desktop (please complete the following information):

    • OS: Fedora 34
    • Browser Firefox 95
    bug 
    opened by statquant 10
  • Error on UpdateRemotePlugins

    Error on UpdateRemotePlugins

    First of all, amazing work! I've been hoping for a hydrogen-like plugin for neovim for quite a while now, and this is looking to be a great implementation.

    Now to the issue, when running UpdateRemotePlugins the following error is thrown:

    Encountered TypeError loading plugin at /home/user/.local/share/nvim/site/pack/packer/start/magma-nvim/rplugin/python3/magma.py: 'type' object is not s
    ubscriptable
    Traceback (most recent call last):
      File "/home/user/.pyenv/versions/nvim-env/lib/python3.8/site-packages/pynvim/plugin/host.py", line 165, in _load
        module = imp.load_module(name, file, pathname, descr)
      File "/usr/lib/python3.8/imp.py", line 234, in load_module
        return load_source(name, filename, file)
      File "/usr/lib/python3.8/imp.py", line 171, in load_source
        module = _load(spec)
      File "<frozen importlib._bootstrap>", line 702, in _load
      File "<frozen importlib._bootstrap>", line 671, in _load_unlocked
    TypeError: 'type' object is not subscriptable
    

    It seems like pynvim isn't recognizing the type annotation syntax from the source file. Removing all indexing from type annotations makes the error go away.

    Not sure if this is an error on my end or if it's a common problem.

    bug 
    opened by JA-Bar 9
  • REQUEST: Helper commands to install compatible kernels

    REQUEST: Helper commands to install compatible kernels

    To make it more user friendly it would be nice to add a option that will install jupyter/ipython/ijulia etc (in MagmaInit, or another command like MagmaInstall). Depending on detected filetype

    enhancement wontfix 
    opened by IndianBoy42 7
  • Install script still refers to

    Install script still refers to "master" branch

    Describe the bug When attempting to install using vim-plug the following error occurs:

    fatal: invalid reference: master
    

    To Reproduce Steps to reproduce the behavior:

    Install the plugin per the instructions for vim-plug, i.e.:

    Plug 'dccsillag/magma-nvim', { 'do': ':UpdateRemotePlugins' }
    

    Expected behavior Vim-plug confirms the plugin installed properly

    Screenshots If applicable, add screenshots to help explain your problem. Screenshot 2022-08-10 at 12 34 44

    Desktop (please complete the following information):

    • OS: MacOS 12.5
    • Browser: N/A
    bug 
    opened by wjdhamilton 6
  • Add kernel interrupt and restart functions

    Add kernel interrupt and restart functions

    Fixes #34

    This adds two new commands, MagmaInterrupt which sends a SIGINT to the kernel, and MagmaRestart which completely restarts the kernel.

    It may be worth to discuss whether MagmaRestart should also clear all output.

    opened by tbung 6
  • Design Questions

    Design Questions

    Hi there.

    Im trying to understand some of the design choices, as Im having trouble with some of the current behaviour. To be more precise, why are you calling MagmaBuffer.clear_interface on every CursorMoved? I would expect this to only be called when the cursor exited a cell / entered a different cell. This causes an excess of ui redraws, and also make it difficult to properly place images using Kitty.

    question 
    opened by tzachar 6
  • Massively slows down startup

    Massively slows down startup

    When my computer is under a moderate load, this plugin appears to be massively slowing down opening time: 1 more second!

    Here's the start of the output of :StartupTime:

           startup: 1949.6
    event                  time percent plot
    BufEnter autocommand 954.79   48.97 ██████████████████████████
    packer_compiled.lua  194.39    9.97 █████▎
    expanding arguments  155.69    7.99 ████▎
    python3.vim          149.25    7.66 ████▏
    init.lua             112.73    5.78 ███▏
    csillag.vim           56.51    2.90 █▌
    filetype.vim          44.51    2.28 █▎
    loading packages      43.17    2.21 █▏
    opening buffers       39.72    2.04 █▏
    loading plugins       32.92    1.69 ▉
    syntax.vim            18.02    0.92 ▌
    synload.vim           17.45    0.90 ▌
    csillag.vim           16.87    0.87 ▌
    rplugin.vim           14.79    0.76 ▍
    rplugin.vim           14.11    0.72 ▍
    indent_blankline.vim  13.74    0.70 ▍
    reading ShaDa         12.14    0.62 ▍
    tcomment.vim          11.61    0.60 ▍
    TabularMaps.vim        9.48    0.49 ▎
    wordmotion.vim         8.41    0.43 ▎
    entire.vim             8.13    0.42 ▎
    first screen update    7.63    0.39 ▎
    
    bug enhancement 
    opened by dccsillag 6
  • [Feature Request] image display on remote desktop through ssh

    [Feature Request] image display on remote desktop through ssh

    Is your feature request related to a problem? Please describe. I'm always frustrated when working with images in Vim, this is an awesome plugin, but I tried on a remote desktop through ssh -X or ssh -Y but the image cannot display

    Describe the solution you'd like The plugin can output the display in nvim on a remote desktop

    enhancement 
    opened by an9236868 5
  • Request - Persistent window and cell delimiters

    Request - Persistent window and cell delimiters

    Interesting plugin! I've been using nvim-ipy with the Jupyter QT console for some time, but having everything in one window sounds a lot nicer. Anyway back to my requests:

    • Would it be possible to have a persistent output window below the executed cell that doesn't cover the code? Something like in this other plugin that reads .ipynb files.

    • Would it be possible to have manual cell delimeters? Something like:

      ##
      cell here
      ##
      

    Edit: Sorry for the mess with the empty issue.

    enhancement passed-on 
    opened by Lun4m 5
  • [Feature Request] Code Folding Support

    [Feature Request] Code Folding Support

    The current case is:

    if there is a block of code (say 10 lines) is folded before the executing line, then the output window will be shifted downwards (10 lines). -------- test.py ----------- print('hello') # if execute this single line there, it works just fine

    +-- 10 lines: ..... ---- # there are 10 lines being folded

    print('hello') # if executing this single line, the output window would be at the bottom. (being shifted downwards 10 lines)

    --------end test.py ---------------------

    Hint of duplicate this issue, set the vim folding method to be "manual" and press zf after selecting the lines in visual mode

    vim.opt.foldmethod = "manual"

    So the essential issue would be when there are too many lines folded, no output window would be shown.

    enhancement 
    opened by TATOAO 0
  • dap does not stop

    dap does not stop

    Hi,

    hope everyone is doing ok. I am currently configuring my setup in AstroNvim, but I am having a little trouble with the debugger dap. I want to debug a big project, and I interact with it via a Notebook but it isn't working for me since magma ignore breakpoints. Thanks, any help will be appreciated. image

    opened by jcvillaquira 0
  • [Feature Request] Create a Special Buffer for Displaying Plots/Images/Non-Text output

    [Feature Request] Create a Special Buffer for Displaying Plots/Images/Non-Text output

    Is your feature request related to a problem? Please describe. Taking inspiration from VSCode, it would be nice if there was a separate buffer for displaying plots.

    Describe the solution you'd like This would be a virtual buffer or something like this that would allow you to maybe split things vertically then have your code file on say the left side, and then the on the right side be maybe a split horizontal that has a Plots buffer and a REPL buffer.

    Describe alternatives you've considered I already keep Jupyter Console open in my tiling window manager but it would be nice to have all this integrated into Neovim

    enhancement 
    opened by usmcamp0811 0
  • [Feature Request] .ipynb support

    [Feature Request] .ipynb support

    nbdev provides some excellent tools for developing with notebooks - particularly their solutions for working within a git repo.

    However, my choices for working with it at the moment are:

    • Use jupyter lab
    • Use VS Code (https://code.visualstudio.com/docs/datascience/jupyter-notebooks)
    • Translate between .ipynb and some other format so I can use neovim

    I'd really like to use the .ipynb files directly within neovim and take advantage of the work that nbdev has done.

    Magma is by far the most usable tool for neovim/jupyter integration that I've used to date. Is it feasible to add support for the .ipynb format without the need for any translation?

    I can see some work done by https://github.com/ahmedkhalf/jupyter-nvim for viewing .ipynb files. That works nicely for me, but the project seems dead and hasn't gone as far as magma.

    enhancement 
    opened by meatballs 1
  • Adding a new command for evaluating in line and instructions for other kernels

    Adding a new command for evaluating in line and instructions for other kernels

    Closes #74

    Jupyter supports any kernel, not just python's. That makes it usable for other languages, such as C# and F#. To use them, you have to make its output mimetype text/plain, that's where we need MagmaEvaluateArgument. Example of this command:

    :MagmaEvaluateArgument a=5;
    

    That will assign 5 to variable a in current context.

    I also added an example of vim commands to add for kernel initialization. That makes it easier to use with, say, telescope. And by default it overwrites mimetype to text/plain for C# and F#.

    Note that I merged @LoipesMas into my fork to make things easier for myself.

    opened by WhiteBlackGoose 1
Owner
Daniel Csillag
Daniel Csillag
🦎 A NeoVim plugin for highlighting visual selections like in a normal document editor!

?? HighStr.nvim A NeoVim plugin for highlighting visual selections like in a normal document editor! Demo TL;DR HighStr.nvim is a NeoVim plugin writte

Pocco81 222 Jan 3, 2023
CLabel is a terminal-based cluster labeling tool that allows you to explore text data interactively and label clusters based on reviewing that data.

CLabel is a terminal-based cluster labeling tool that allows you to explore text data interactively and label clusters based on reviewing that

Peter Baumgartner 29 Aug 9, 2022
Neovim integration for Google Keep, built using gkeepapi

Gkeep.nvim Neovim integration for Google Keep, built using gkeepapi Requirements Neovim 0.5 Python 3.6+ A patched font (optional. Used for icons) Tabl

Steven Arcangeli 143 Jan 2, 2023
Freaky fast fuzzy Denite/CtrlP matcher for vim/neovim

Freaky fast fuzzy Denite/CtrlP matcher for vim/neovim This is a matcher plugin for denite.nvim and CtrlP.

Raghu 113 Sep 29, 2022
Bringing emacs' greatest feature to neovim - Tetris!

nvim-tetris Bringing emacs' greatest feature to neovim - Tetris! This plugin is written in Fennel using Olical's project Aniseed for creating the proj

null 129 Dec 26, 2022
🌈 Generate color palettes based on Neovim colorschemes.

Iris Iris is a Neovim plugin that generates a normalized color palette based on your colorscheme. It is named for the goddess Iris of Greek mythology,

N. G. Scheurich 45 Jul 28, 2022
Euporie is a text-based user interface for running and editing Jupyter notebooks

Euporie is a text-based user interface for running and editing Jupyter notebooks

null 781 Jan 1, 2023
Open a file in your locally running Visual Studio Code instance from arbitrary terminal connections.

code-connect Open a file in your locally running Visual Studio Code instance from arbitrary terminal connections. Motivation VS Code supports opening

Christian Volkmann 56 Nov 19, 2022
Lets you view, edit and execute Jupyter Notebooks in the terminal.

Lets you view, edit and execute Jupyter Notebooks in the terminal.

David Brochart 684 Dec 28, 2022
Ipylivebash - Run shell script in Jupyter with live output

ipylivebash ipylivebash is a library to run shell script in Jupyter with live ou

Ben Lau 6 Aug 27, 2022
A simple python application for running a CI pipeline locally

A simple python application for running a CI pipeline locally This app currently supports GitLab CI scripts

Tom Stowe 0 Jan 11, 2022
A ZSH plugin that enables you to use OpenAI's powerful Codex AI in the command line.

A ZSH plugin that enables you to use OpenAI's powerful Codex AI in the command line.

Tom Dörr 976 Jan 3, 2023
A CLI Spigot plugin manager that adheres to Unix conventions and Python best practices.

Spud A cross-platform, Spigot plugin manager that adheres to the Unix philosophy and Python best practices. Some focuses of the project are: Easy and

Tommy Dougiamas 9 Dec 2, 2022
🐍The nx-python plugin allows users to create a basic python application using nx commands.

?? NxPy: Nx Python plugin This project was generated using Nx. The nx-python plugin allows users to create a basic python application using nx command

StandUP Communications 74 Aug 31, 2022
A minimalist Vim plugin manager.

A minimalist Vim plugin manager. Pros. Easy to set up: Single file. No boilerplate code required. Easy to use: Concise, intuitive syntax Super-fast pa

Junegunn Choi 30.2k Jan 8, 2023
Lsp Plugin for working with Python virtual environments

py_lsp.nvim What is py_lsp? py_lsp.nvim is a neovim plugin that helps with using the lsp feature for python development. It tackles the problem about

Patrick Haller 55 Dec 27, 2022
Seamlessly run Python code in IPython from Vim

Seamlessly run Python code from Vim in IPython, including executing individual code cells similar to Jupyter notebooks and MATLAB. This plugin also supports other languages and REPLs such as Julia.

Hans Chen 269 Dec 20, 2022
A terminal UI dashboard to monitor requests for code review across Github and Gitlab repositories.

A terminal UI dashboard to monitor requests for code review across Github and Gitlab repositories.

Kyle Harrison 150 Dec 14, 2022
Easy-to-use terminal program that can compile your code.

Description Easy-to-use terminal program that can compile your code. Installition 1. Cloning repository $ git clone https://github.com/DarkJoij/Compil

DarkJoij 1 Oct 21, 2021