martanne / vis

A vi-like editor based on Plan 9's structural regular expressions
Other
4.19k stars 259 forks source link

Feature Request: Deep Set Operations on Selections #1078

Closed jeremybobbin closed 1 year ago

jeremybobbin commented 1 year ago

I'd like to see further elaboration on set operations in selections. For example:

void cat() {
    eat();
    meow();
    drink();
    purr();
    sleep();
}

void dog() {
    eat();
    bark();
    drink();
    growel();
    sleep();
}

Let's say I run /cat/,/\}$/ x/.*;$/ to select all function calls in cat, save that in the register, then do the same for dog: /dog/,/\}$/ x/.*;$/.

One should be able to take (deeply) intersecting selections(< & > will selection start & end):

void cat() {
  < eat();   >
    meow();
  < drink(); >
    purr();
  < sleep(); >
}

void dog() {
  < eat();   >
    bark();
  < drink(); >
    growl();
  < sleep(); >
}

And maybe subtraction:

void dog() {
    eat();  
  < bark();   >
    drink();  
  < growl();  >
    sleep();  
}

Any way to do this? Does this sound useful? Thanks

ninewise commented 1 year ago

You could do this using the lua API:

  1. save the current selection contents in a lua list
  2. run vis.mark and | to get the union of the selections
  3. iterate over these and do your set thing, constructing a new selection along the way

Documentation here: https://martanne.github.io/vis/doc/index.html

jeremybobbin commented 1 year ago

Thanks for sharing @ninewise

Seems like we couldn't do that without Selection:remove: https://github.com/martanne/vis/pull/1080

For you or anyone else who's curious:

-- pairwise selection set operations
local intersection = function(file, mark, sel)
    local keep = false
    for i = 1, #mark do
        local mr = { start = mark[i].start, finish = mark[i].finish }
        if file:content(sel.range) == file:content(mr) then
            keep = true
        end
    end

    if not keep then
        sel:remove()
    end
end

-- fn iterates over marks to compare them to (& operate on) the single selection
local pairwise = function(fn)
    local win = vis.win
    local sels = win.selections

    for i = 1, #sels do
        if sels[i] ~= nil and sels[i].range ~= nil then
            fn(win.file, win.marks[vis.mark], sels[i])
        end
    end
end

vis:map(vis.modes.VISUAL, "z&", function() pairwise(intersection) end, "Pairwise intersection with register")
mcepl commented 1 year ago

@jeremybobbin you mean something like https://git.sr.ht/~mcepl/vis-selections/tree/master/item/init.lua ?

How exactly should I test it?

jeremybobbin commented 1 year ago

Oh! Thanks for hosting it :) Just like this - a demonstration of pairwise-intersection: https://asciinema.org/a/bFmljEEQTVDrwkMLG2Y7I9svk

I saw Martanne had a (buggy) implementation of these operations in ~v0.5, describing them as "pairwise" operations with a few varients - here's the section from the old help page:

  z&                    Pairwise intersect with selections from register
  z+                    Pairwise combine: take longer
  z-                    Pairwise combine: take shorter
  z<                    Pairwise combine: leftmost
  z>                    Pairwise combine: rightmost

This is a live demonstration of z&, for the use-case described here: https://asciinema.org/a/bFmljEEQTVDrwkMLG2Y7I9svk

I'd like to see these implemented in C again(correctly), and I'd like to see these operations be doable from the sam interpreter. The above demo could be described in one line:

/cat/,/\}$/ x/^.*$/ g/^\t/ y/\t/   z&   /dog/,/\}$/ x/^.*$/ g/^\t/ y/\t/

I believe Martanne was onto something incredibly useful with this, though the real-world use-cases still seem vague in my mind.

mcepl commented 1 year ago

Could you make a diff between your current branch and devel branch of https://git.sr.ht/~mcepl/vis , please? I think we have something very different somewhere.

mcepl commented 1 year ago

Could you make a diff between your current branch and devel branch of https://git.sr.ht/~mcepl/vis , please? I think we have something very different somewhere.

Hmm, the big one seems to be https://github.com/martanne/vis/pull/675 which should really really be merged. @ninewise ?

jeremybobbin commented 1 year ago

This was way back in v0.5. I only know about this because I was looking at the help page from Ubuntu's vis distribution.

See main.c:1101 in 78d6ae