Code Monkey home page Code Monkey logo

nvim-femaco.lua's Introduction

FeMaco

โ— Originally this was written for only markdown code blocks. However this plugin now support any language injection in any language!

Catalyze your Fenced Markdown Code-block editing!

FeMoco_cluster (based on this)

A small plugin allowing to edit injected language trees with correct filetype in a floating window. This allows you to use all of your config for your favorite language. The buffer will be also linked to a temporary file in order to allow LSPs to work properly.

Powered by treesitter, lua and coffee.

femaco.mp4

Installation

For example using packer:

use {
  'AckslD/nvim-FeMaco.lua',
  config = 'require("femaco").setup()',
}

Requires nvim-treesitter.

Configuration

Pass a dictionary into require("femaco").setup() with callback functions. These are the defaults:

require('femaco').setup({
  -- should prepare a new buffer and return the winid
  -- by default opens a floating window
  -- provide a different callback to change this behaviour
  -- @param opts: the return value from float_opts
  prepare_buffer = function(opts)
    local buf = vim.api.nvim_create_buf(false, false)
    return vim.api.nvim_open_win(buf, true, opts)
  end,
  -- should return options passed to nvim_open_win
  -- @param code_block: data about the code-block with the keys
  --   * range
  --   * lines
  --   * lang
  float_opts = function(code_block)
    return {
      relative = 'cursor',
      width = clip_val(5, 120, vim.api.nvim_win_get_width(0) - 10),  -- TODO how to offset sign column etc?
      height = clip_val(5, #code_block.lines, vim.api.nvim_win_get_height(0) - 6),
      anchor = 'NW',
      row = 0,
      col = 0,
      style = 'minimal',
      border = 'rounded',
      zindex = 1,
    }
  end,
  -- return filetype to use for a given lang
  -- lang can be nil
  ft_from_lang = function(lang)
    return lang
  end,
  -- what to do after opening the float
  post_open_float = function(winnr)
    vim.wo.signcolumn = 'no'
  end
  -- create the path to a temporary file
  create_tmp_filepath = function(filetype)
    return os.tmpname()
  end,
  -- if a newline should always be used, useful for multiline injections
  -- which separators needs to be on separate lines such as markdown, neorg etc
  -- @param base_filetype: The filetype which FeMaco is called from, not the
  -- filetype of the injected language (this is the current buffer so you can
  -- get it from vim.bo.filetyp).
  ensure_newline = function(base_filetype)
    return false
  end,
  -- Return true if the indentation should be normalized. Useful when the
  -- injected language inherits indentation from the construction scope (e.g. an
  -- inline multiline sql string). If true, the leading indentation is detected,
  -- stripped, and restored before/after editing.
  --
  -- @param base_filetype: The filetype which FeMaco is called from, not the
  -- filetype of the injected language (this is the current buffer, so you can
  -- get it from vim.bo.filetype).
  normalize_indent = function (base_filetype)
    return false
  end
})

Usage

Call :FeMaco or require('femaco.edit').edit_code_block() with your cursor on a code-block. Edit the content, then save and/or close the popup to update the original buffer.

Credit

Thanks to everyone working on neovim core, lua-api, treesitter etc which have made plugins like these a joy to create!

nvim-femaco.lua's People

Contributors

acksld avatar axieax avatar christoffer avatar zhengpd avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar

nvim-femaco.lua's Issues

[feat] use same buffer for multiple code chunks (+ collaboration ideas)

Hi there, really cool plugin! I love your idea of using floating windows.

I have been trying to implement code completion, dignostics and the likes for https://github.com/quarto-dev/quarto-nvim, the neovim plugin for quarto (plain text computational notebooks for R / python / julia / java script which you can render to any output format, such as presentations, websites, pdfs etc.).

Would you be open to contributions to increase interoperability between the plugins? For example, one feature I would love to port to your plugin is the ability to use the same buffer / temporary file for all code chunks of the same language within one document.

This would mean, that e.g.

```{python}
def hello():
  print('hello')
```

```{python}
hello()
```

wouldn't suffer from
image

I have a function to create a hidden buffer (coupled to a file) with the language content of a file (via treesitter), that can be synchronized to the source document and shares line numbers because the non-language lines are simply set to empty lines: https://github.com/quarto-dev/quarto-nvim/blob/ab3995baa8e975718ba7023451b7a2a308a876e2/lua/quarto/init.lua#L134-L163

My struggle was with showing things from this hidden buffer in the main source document, but I think your idea solves this very elegantly!

Add alternate styling to render window in-buffer using virtual lines

Hi @AckslD,

Really cool plugin ๐Ÿš€ . I saw the initial announcement and someone suggested this idea which seemed really cool, but didn't raise an issue for it, so I thought I would to see what your thoughts are on it. I think it would be a really nice workflow/UI if rather than a floating window with a border the window overlaid the code block (if possible, could just be beneath if it is not multiline), and using virtual lines it expanded the buffer, so you could edit it as though it were part of the buffer.

I'm not sure if there are complex edge cases to consider here, but thought I'd raise it officially

Compatibility with norg?

Trying to use this with https://github.com/nvim-neorg/neorg

The good news is using :FeMaco does work and displays the float with the code, and I think it's highlighted correctly.

The bad news if I invoke some form of :wq after adding some lines, it replaces the @end tag with the new line.

2022-09-19 19 22 11

Nothing happend after call `:FeMaco`

Install using Lazy.nvim as follow:

{'AckslD/nvim-FeMaco.lua', config = function()
      require("femaco").setup{}
end, lazy = false},

Neovim version: 0.9.4

Question: future of nvim-FeMaco.lua

Hello AcksID, thanks for writing such a cool plugin. I think it paves the way for a feature I see (in due time) being in the neovim ecosystem: fully supported injection LSP seamlessly integrated with code editing.

I have two questions for now:

  1. How can I configure nvim-FeMaco to work with javascript inside of a <script> tag in HTML? Understanding this example I think will help me figure out how any injected language can work.
  2. How far off is seamless LSP integration with injected langauges (i.e., not needing a floating window? - like otter.nvim, except, well, it actually works)

Thanks for your work!

Detect FeMaco buffer on LSP attach

First of all thanks for this plugin, is a great idea.

My problem: when I edit a code block with require('femaco.edit').edit_code_block() [1] the floating buffer recognizes the filetype (syntax highlighting works for example) but the LSP integration (nvim official) is not usable, depending on your configuraiton. For example, if normally errors will be shown in the gutter it won't be visible as there are no line numbers. Same thing with errors/warnings indicators in the status line or the quickfix (it's open in the buffer behing the floating one).

For example, I'd like to enable virtual text or underline to show errors but only in the floating buffer and disable some stuff.
It's possible to detect a "FeMaco" buffer when LSP attachs to it?

Thanks!


[1] the command FeMaco does not exist for some reason, running neovim 0.8

Error when use command `:Femaco`

I use default configure with setup, but will cause error:

Error executing Lua callback: /usr/share/nvim/runtime/lua/vim/treesitter.lua:189: attempt to index local 'node_or_range' (a nil value)
stack traceback:
	/usr/share/nvim/runtime/lua/vim/treesitter.lua:189: in function 'get_match_range'
	...ocal/share/nvim/lazy/nvim-FeMaco.lua/lua/femaco/edit.lua:84: in function 'get_match_at_cursor'
	...ocal/share/nvim/lazy/nvim-FeMaco.lua/lua/femaco/edit.lua:156: in function 'edit_code_block'
	...ocal/share/nvim/lazy/nvim-FeMaco.lua/lua/femaco/init.lua:12: in function <...ocal/share/nvim/lazy/nvim-FeMaco.lua/lua/femaco/init.lua:12>

I can confirm:

  • Neovim is the latest nightly version
  • All treesitters are updated

Handle language specific settings

I'm trying to create a language specific settings for FeMaco and rust. So far I got this working, but it seems pretty hacky. Is there a better, idiomatic way to configure language specific behavior in FeMaco?

I have also thought about creating a user command, but this was easier.

require('femaco').setup({
  -- return filetype to use for a given lang
  -- lang can be nil
  ft_from_lang = function(lang)
    Language = lang
    return lang
  end,
  -- what to do after opening the float
  post_open_float = function(winnr)
    if Language == "rust" then
      require('rust-tools.standalone').start_standalone_client()
    end
  end
})

Split or separate buffer instead of floating window

Hello, this plugin is great! However, I was wondering if there was an option to open the code in a separate buffer or split instead of a floating window, or if there were any plans to implement this feature.

Incorrect indentation in org-mode

Reproduction

  1. Enable indentation in org_mode (default) or set org_indent_mode to indent
  2. Create at least two levels of headlines and add a src block (see example below)
  3. Invoke the FeMaco binding on the src block
  4. Update the src block content indentation (like ggVG=)
  5. Use the :wq command to write and replace prev src block

Example

#+title: Org FeMaco Indentation Repro

* Heading 1

  ** Heading 2

     #+begin_src fennel
     (let [x 5]
     (+ x 2)) ;; Purposefully incorrectly indented 
     #+end_src

Expected

The indentation level after saving the FeMaco buffer should respect the original org-mode src block indentation

* Heading 1

  ** Heading 2

     #+begin_src fennel
     (let [x 5]
       (+ x 2)) ;; Now correctly indented 
     #+end_src

Actual

The indentation level does not reflect the org-mode src block indentation:

* Heading 1

  ** Heading 2

     #+begin_src fennel
     (let [x 5]
(+ x 2)) ;; Now worse than before :(
     #+end_src

Workarounds

  • For now I've just set org_indent_mode to noindent

Error: attempt to call field 'get_node_range' (a nil value)

Hey there! This is a really cool plugin. Thank you for sharing it!

When I try to use it by running :FeMaco with the cursor in a code block, I get this error:

Error executing Lua callback: ...te/pack/packer/start/nvim-FeMaco.lua/lua/femaco/edit.lua:33: attempt to call field 'get_node
_range' (a nil value)                                                                                                        
stack traceback:                                                                                                             
        ...te/pack/packer/start/nvim-FeMaco.lua/lua/femaco/edit.lua:33: in function 'get_match_range'                        
        ...te/pack/packer/start/nvim-FeMaco.lua/lua/femaco/edit.lua:79: in function 'get_match_at_cursor'                    
        ...te/pack/packer/start/nvim-FeMaco.lua/lua/femaco/edit.lua:139: in function 'edit_code_block'                       
        ...te/pack/packer/start/nvim-FeMaco.lua/lua/femaco/init.lua:10: in function <...te/pack/packer/start/nvim-FeMaco.lua/
lua/femaco/init.lua:10>

I'm on neovim v0.7.2 on Linux. I used Packer to install the plugin as shown in the README, and I do have treesitter set up.

Any idea what's going wrong? Happy to provide additional info and help troubleshoot however I can.

recording.mp4

Expand `float_opts` with user's options

Hi there,

at the moment in order to change border configuration user has to provide all of the other required keys in table returned from float_opts. It would be better user experience if returned table got merged with default one so only keys that user wants changing would have to be supplied. At the moment users might want to keep an eye on internal implementation and maintain its copy within their configurations.

Thanks for great plugin!

Support for inline injections

If we support arbitrary injections (#4 #3) then these might also be inline. Currently we assume that the content of the injection are on separate lines compared to the rest. This should be relatively simple to fix by eg using nvim_buf_set_text instead of nvim_buf_set_lines.

nvim-treesitter changed @language to @_lang in injections.scm for markdown

nvim-treesitter/nvim-treesitter@cdc45ac#diff-5328c9ed744eb360fb6d970de5378d453bacfab5479fd7b05ca216e5a8f2652d

I have just installed your plugin, so I am not very familiar with the code yet, but I had to change edit.lua:parse_match() to use match._lang instead of match.language for the floating window to get the correct file type. I see for other types of documents they still use @language, so maybe parse_match() needs to account for that?

Thanks!

Can `FeMaco` add a mechanism for clean temp file

Thanks for this plugin.

I have a slight issue with Femaco, when I use FeMaco to edit inline code block in a floating window, the formatter tool don't be affected by config (e.g., .stylua.tomal for stylua). I realized that FeMaco create temp file use os.tmpname() default, which return /temp/lua_xxxx, it is out of source folder.

So I add customize post_open_float and create_tmp_filepath for the purpose of creating tempfile in source folder

local function femaco()
    local cache_filename
    require("femaco").setup({
        post_open_float = function(winnr)
            print(string.format("post_open_float: %s", winnr))
            vim.api.nvim_create_autocmd("WinClosed", {
                pattern = "*",
                callback = function()
                    local closed_win = vim.fn.expand("<amatch>")
                    if tonumber(closed_win)== winnr then
                        print(string.format("remove temp file %s", cache_filename))
                        vim.loop.fs_unlink(cache_filename)
                    end
                end,
            })
        end,
        create_tmp_filepath = function(filetype)
            cache_filename = string.format("%s/.femaco_%d_%s", vim.fn.getcwd(), math.random(100, 999), filetype)
            return cache_filename
        end,
    })
end

everything works perfect until I open multiple FeMaco floating windows to edit different code blocks. the cache_filename will be override, so some tempfile will not be clean right.

could FeMaco add ability to cleanup temp file?

Refer to null-ls.nvim, which need tempfile to format file sameily

https://github.com/jose-elias-alvarez/null-ls.nvim/blob/db09b6c691def0038c456551e4e2772186449f35/lua/null-ls/helpers/generator_factory.lua#L300-L311

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.