# Ripgrep Search with View API

**URL:** https://community.silverbullet.md/t/ripgrep-search-with-view-api/4350
**Category:** Edge
**Created:** [August 31, 2026, 7:44am UTC](https://community.silverbullet.md/t/ripgrep-search-with-view-api/4350 "2026-08-31T07:44:24Z")
**Posts on this page:** 6
**Page:** 1

<div class="post-metadata">

### Author: ![LogeshG5](https://community.silverbullet.md/user_avatar/community.silverbullet.md/logeshg5/32/1171_2.png) [@LogeshG5](https://community.silverbullet.md/u/LogeshG5)
#### Post date: [August 31, 2026, 7:44am UTC](https://community.silverbullet.md/t/ripgrep-search-with-view-api/4350/1 "2026-08-31T07:44:24Z")

</div>

I tried the new [View API](https://edge.silverbullet.md/API/view) on the Edge release.

I implemented a search with [ripgrep](https://github.com/burntsushi/ripgrep). You select a text and run `Navigate: RG Search`.

 ![image](https://community.silverbullet.md/uploads/default/original/2X/b/b5a885e48c9f9e01c3cd35470bedff01a18ff09e.png)

It works fine, and I see it needs improvements,

1. Ability to update the search when filter text is updated
2. Ability to highlight the selected text
3. Ability to add custom buttons like `Match Case`, `Regex`

Suggestions on how to improve is welcomed. @zef, Are these use-cases overkill / possible?

```lua
rgsearch = rgsearch or {}
function rgsearch.parseRgOutput(rgJsonOutput)

  local results = {}

  for line in rgJsonOutput:gmatch("[^\r\n]+") do
      parsed = js.tolua(js.window.JSON.parse(line))
      print(parsed.type)

      if parsed.type == "match" and parsed.data then
        print(parsed, 'parsed')
        local data = parsed.data
        local fullPath = data.path and data.path.text or ""
        local rawLine = data.lines and data.lines.text or ""

        -- Clean trailing newline/carriage returns and path separators
        local cleanLine = string.gsub(rawLine, "[\r\n]", "")
        local cleanLine = string.gsub(cleanLine, "/", "\\")

        -- Extract just the filename from path (e.g., "docs/Journal/Week/2026-08-03.md" -> "2026-08-03.md")
        local fileName = string.match(fullPath, "[^/]+$") or fullPath

        -- Build submatches table
        local submatches = {}
        if data.submatches then
          for _, sub in ipairs(data.submatches) do
            table.insert(submatches, {
              text = sub.match and sub.match.text or "",
              startCol = sub.start,
              endCol = sub["end"]
            })
          end
        end

        -- Construct name: <filename>/<line content preview>
        local namePath = fileName .. "/" .. cleanLine

        table.insert(results, {
          name = namePath,
          path = fullPath,
          lineNumber = data.line_number,
          offset = data.absolute_offset,
          line = cleanLine,
          submatches = submatches
        })
    end
  end
  return results
end

view.define {
  name = "RG Search",
  title = "Search",
  command = "Navigate: RG Search",
  dock = "modal",
  supportedDocks = { "page-top", "page-bottom", "lhs", "rhs", "modal" },
  defaultOpen = true,
  key = "Ctrl-Shift-f",
  mac = "Cmd-Shift-f",
  source = function(ctx)
    local term = editor.getSelection().text
    local result = shell.run("rg", {"-nbiu", "--json", "--column", "--type", "markdown", term})
    local searchdata = rgsearch.parseRgOutput(result.stdout)
    return searchdata;
  end,
  presentation = {
    mode = "tree",
    row = {
      primary = "name",
      description = "page"
    },
    expandAll = true,
  },
  onSelect = function(item)
    editor.navigate(item.path .. '@' .. item.offset)
  end,
  onCreate = function(item)
    print(item)
  end,
}

```

If interested, I have another library implementing the search with RG - [silverbullet-libraries/RG Search.md at main · LogeshG5/silverbullet-libraries · GitHub](https://github.com/LogeshG5/silverbullet-libraries/blob/main/RG%20Search.md)

---

<div class="post-metadata">

### Author: ![zef](https://community.silverbullet.md/user_avatar/community.silverbullet.md/zef/32/7_2.png) [@zef](https://community.silverbullet.md/u/zef)
#### Post date: [August 31, 2026, 8:29am UTC](https://community.silverbullet.md/t/ripgrep-search-with-view-api/4350/2 "2026-08-31T08:29:47Z")

</div>

Nice! I think this is a great use, and one of the goals of SB is to provide infrastructure that people can then do surprising things with. I didn't anticipate this one, but I like it.

Looking at this example, specifically your `source` function, this is passed `ctx` which should have a `phrase` field containing the current search phrase, which you may want to use instead of the editor selection. Then, if you switch the `search` field to `source`, it will basically re-run the `source` function on every keystroke (debounced), fetching results from ripgrep based on the search phrase.

You'll have to experiment and see if this all works as it's supposed to (this part is not very well tested).

Docs (which I hope you found): [view](https://edge.silverbullet.md/API/view)

---

<div class="post-metadata">

### Author: ![LogeshG5](https://community.silverbullet.md/user_avatar/community.silverbullet.md/logeshg5/32/1171_2.png) [@LogeshG5](https://community.silverbullet.md/u/LogeshG5)
#### Post date: [August 31, 2026, 12:09pm UTC](https://community.silverbullet.md/t/ripgrep-search-with-view-api/4350/3 "2026-08-31T12:09:44Z")

</div>

Thanks Zef. It worked.

 ![image](https://community.silverbullet.md/uploads/default/original/2X/6/65bc7c60be425b042ac71f8c57207e846da1b440.png)

Wishes,

1. Ability to add custom buttons like Match Case, Regex for extra control, I see an ability to have dropdowns, so custom widgets might be possible one day

```lua
rgsearch = rgsearch or {}
function rgsearch.parseRgOutput(rgJsonOutput)

  local results = {}

  for line in rgJsonOutput:gmatch("[^\r\n]+") do
      parsed = js.tolua(js.window.JSON.parse(line))

      if parsed.type == "match" and parsed.data then
        local data = parsed.data
        local fullPath = data.path and data.path.text or ""
        local rawLine = data.lines and data.lines.text or ""

        -- Clean trailing newline/carriage returns
        local cleanLine = string.gsub(rawLine, "[\r\n]", "")

        -- Extract just the filename from path (e.g., "docs/Journal/Week/2026-08-03.md" -> "2026-08-03.md")
        local fileName = string.match(fullPath, "[^/]+$") or fullPath

        -- Build submatches table
        local submatches = {}
        if data.submatches then
          for _, sub in ipairs(data.submatches) do
            table.insert(submatches, {  
              text = sub.match and sub.match.text or "",
              startCol = sub.start,
              endCol = sub["end"]
            })
          end
        end

        -- Construct name: <filename>/<line content preview>
        local namePath = fileName .. "\31" .. cleanLine

        table.insert(results, {
          name = namePath,
          path = fullPath,
          lineNumber = data.line_number,
          offset = data.absolute_offset,
          line = cleanLine,
          submatches = submatches
        })
    end
  end
  return results
end

view.define {
  name = "RG Search",
  title = "Search",
  command = "Navigate: Search",
  dock = "modal",
  supportedDocks = { "page-top", "page-bottom", "lhs", "rhs", "modal" },
  defaultOpen = true,
  key = "Ctrl-Shift-f",
  mac = "Cmd-Shift-f",
  source = function(ctx)
    local term = ctx.phrase
    if #term == 0 then 
      term = editor.getSelection().text 
    end
    if #term < 3 then return end
    local result = shell.run("rg", {"-nbiu", "--json", "--column", "--type", "markdown", term})
    local searchdata = rgsearch.parseRgOutput(result.stdout)
    return searchdata;
  end,
  search = "source",
  presentation = {
    mode = "tree",
    hierarchy = { field = "name", separator = "\31"},
    row = {
      primary = "name",
      description = "page",
      icon = function(obj) if obj.isFolder then return 'file-text' end end,
    },
    expandAll = true,
  },
  onSelect = function(item)
    editor.navigate(item.path .. '@' .. item.offset)
  end,
}

```

---

<div class="post-metadata">

### Author: ![adxsoft](https://community.silverbullet.md/user_avatar/community.silverbullet.md/adxsoft/32/2789_2.png) [@adxsoft](https://community.silverbullet.md/u/adxsoft)
#### Post date: [September 4, 2026, 10:50am UTC](https://community.silverbullet.md/t/ripgrep-search-with-view-api/4350/4 "2026-09-04T10:50:28Z")

</div>

Is the view API available on 2.10.0-0-g2b2a7c71-2026-07-28T12-40-06Z.

---

<div class="post-metadata">

### Author: ![zef](https://community.silverbullet.md/user_avatar/community.silverbullet.md/zef/32/7_2.png) [@zef](https://community.silverbullet.md/u/zef)
#### Post date: [September 4, 2026, 6:12pm UTC](https://community.silverbullet.md/t/ripgrep-search-with-view-api/4350/5 "2026-09-04T18:12:07Z")

</div>

No, it will be in 2.11

---

<div class="post-metadata">

### Author: ![adxsoft](https://community.silverbullet.md/user_avatar/community.silverbullet.md/adxsoft/32/2789_2.png) [@adxsoft](https://community.silverbullet.md/u/adxsoft)
#### Post date: [September 5, 2026, 12:26am UTC](https://community.silverbullet.md/t/ripgrep-search-with-view-api/4350/6 "2026-09-05T00:26:59Z")

</div>

thanks .. look forward to using the View API
