Skip to content

Commit

Permalink
feat: highlight the currently hovered file in yazi (opt-in)
Browse files Browse the repository at this point in the history
For now, this change is opt-in (disabled by default).

This change makes it possible to highlight the currently hovered file with a
style of the user's own choosing.

To enable it, you need to do the following steps in your configuration:

- set `use_ya_for_events_reading = true`
- set these new settings in your configuration:

  ```lua
  ---@type LazySpec
  {
    "mikavilpas/yazi.nvim",
    -- ...other settings you might already have
    ---@type YaziConfig
    opts = {
      -- add these:
      use_ya_for_events_reading = true,
      highlight_groups = {
        hovered_buffer_background = { bg = "#363a4f" },
      },
      -- ...other settings you might already have
    }
  }
  ```

For now, the color needs to be configured manually. In the future we may have a
good default color. If you use catppuccin, you can find all the colors in the
palette here: <https://catppuccin.com/palette>. I used the `Surface 0` color
from my catppuccin macchiato palette.
  • Loading branch information
mikavilpas committed Jul 12, 2024
1 parent 34aaf69 commit b249ec4
Show file tree
Hide file tree
Showing 16 changed files with 502 additions and 26 deletions.
7 changes: 7 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -124,6 +124,13 @@ You can optionally configure yazi.nvim by setting any of the options below.
-- https://github.com/mikavilpas/yazi.nvim/pull/152
use_ya_for_events_reading = false,

-- an upcoming optional feature. See
-- https://github.com/mikavilpas/yazi.nvim/pull/180
highlight_groups = {
-- NOTE: this only works if `use_ya_for_events_reading` is enabled, etc.
hovered_buffer_background = nil,
},

-- the floating window scaling factor. 1 means 100%, 0.9 means 90%, etc.
floating_window_scaling_factor = 0.9,

Expand Down
4 changes: 3 additions & 1 deletion integration-tests/client/testEnvironmentTypes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,8 @@ export type StartNeovimServerArguments = {
} & StartNeovimArguments

export type StartupScriptModification =
"modify_yazi_config_to_use_ya_as_event_reader.lua"
| "modify_yazi_config_to_use_ya_as_event_reader.lua"
| "modify_yazi_config_and_add_hovered_buffer_background.lua"

declare global {
interface Window {
Expand Down Expand Up @@ -54,6 +55,7 @@ export type TestDirectory = {
["initial-file.txt"]: FileEntry
["test.lua"]: FileEntry
["file.txt"]: FileEntry
["modify_yazi_config_to_use_ya_as_event_reader.lua"]: FileEntry
["subdirectory/sub.txt"]: FileEntry
["routes/posts.$postId/route.tsx"]: FileEntry
["routes/posts.$postId/adjacent-file.tsx"]: FileEntry
Expand Down
5 changes: 5 additions & 0 deletions integration-tests/cypress.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,11 @@ export default defineConfig({
stem: "sub",
extension: ".txt",
},
"modify_yazi_config_to_use_ya_as_event_reader.lua": {
name: "modify_yazi_config_to_use_ya_as_event_reader.lua",
stem: "modify_yazi_config_to_use_ya_as_event_reader",
extension: ".lua",
},
"routes/posts.$postId/adjacent-file.tsx": {
name: "adjacent-file.tsx",
stem: "adjacent-file",
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,201 @@
import { flavors } from "@catppuccin/palette"
import { startNeovimWithYa } from "./startNeovimWithYa"

const surface0 = flavors.macchiato.colors.surface1.rgb
const base = flavors.macchiato.colors.base.rgb

function rgbify(color: typeof surface0) {
return `rgb(${color.r.toString()}, ${color.g.toString()}, ${color.b.toString()})`
}

describe("highlighting the buffer with 'hover' events", () => {
beforeEach(() => {
cy.visit("http://localhost:5173")
})

const backgroundColors = {
normal: rgbify(base),
hovered: rgbify(surface0),
} as const

// NOTE: when opening the file, the cursor is placed at the beginning of
// the file. This causes the web terminal to render multiple elements for the
// same text, and this can cause issues when matching colors, as in the DOM
// there are multiple colors. Work around this by matching a substring of the
// text instead of the whole text.

/** HACK in CI, there can be timing issues where the first hover event is
* lost. Right now we work around this by selecting another file first, then
* hovering the desired file.
*/
function hoverAnotherFileToEnsureHoverEventIsReceivedInCI(file: string) {
// select another file (hacky)
cy.typeIntoTerminal("gg")

// select the desired file so that a new hover event is sent
cy.typeIntoTerminal(`/${file}{enter}`)
}

it("can highlight the buffer when hovered", () => {
startNeovimWithYa({
startupScriptModifications: [
"modify_yazi_config_and_add_hovered_buffer_background.lua",
],
}).then((dir) => {
// wait until text on the start screen is visible
cy.contains("If you see this text, Neovim is ready!")
.children()
.should("have.css", "background-color", backgroundColors.normal)

// start yazi
cy.typeIntoTerminal("{upArrow}")

hoverAnotherFileToEnsureHoverEventIsReceivedInCI(
dir.contents["initial-file.txt"].name,
)

// yazi is shown and adjacent files should be visible now
//
// the current file (initial-file.txt) is highlighted by default when
// opening yazi. This should have sent the 'hover' event and caused the
// Neovim window to be shown with a different background color
cy.contains("If you see this text, Neovim is ready!").should(
"have.css",
"background-color",
backgroundColors.hovered,
)

// close yazi - the highlight should be removed and we should see the
// same color as before
cy.typeIntoTerminal("q")
cy.contains("Neovim is ready!").should(
"have.css",
"background-color",
backgroundColors.normal,
)
})
})

it("can remove the highlight when the cursor is moved away", () => {
startNeovimWithYa({
startupScriptModifications: [
"modify_yazi_config_and_add_hovered_buffer_background.lua",
],
}).then((dir) => {
// wait until text on the start screen is visible
cy.contains("Neovim is ready!").should(
"have.css",
"background-color",
backgroundColors.normal,
)

// start yazi
cy.typeIntoTerminal("{upArrow}")

// yazi is shown and adjacent files should be visible now
cy.contains(dir.contents["test.lua"].name)

hoverAnotherFileToEnsureHoverEventIsReceivedInCI(
dir.contents["initial-file.txt"].name,
)

// the current file (initial-file.txt) is highlighted by default when
// opening yazi. This should have sent the 'hover' event and caused the
// Neovim window to be shown with a different background color
cy.contains("Neovim is ready!").should(
"have.css",
"background-color",
backgroundColors.hovered,
)

// hover another file - the highlight should be removed
cy.typeIntoTerminal(`/^${dir.contents["test.lua"].name}{enter}`)

cy.contains("Neovim is ready!").should(
"have.css",
"background-color",
backgroundColors.normal,
)
})
})

it("can move the highlight to another buffer when hovering over it", () => {
startNeovimWithYa({
startupScriptModifications: [
"modify_yazi_config_and_add_hovered_buffer_background.lua",
],
}).then((dir) => {
// wait until text on the start screen is visible
cy.contains("If you see this text, Neovim is ready!")
.children()
.should("have.css", "background-color", backgroundColors.normal)

const testFile = dir.contents["test.lua"].name
// open an adjacent file and wait for it to be displayed
cy.typeIntoTerminal(`:vsplit ${dir.rootPath}/${testFile}{enter}`, {
delay: 1,
})
cy.contains("how to initialize the test environment")

// start yazi - the initial file should be highlighted
cy.typeIntoTerminal("{upArrow}")

hoverAnotherFileToEnsureHoverEventIsReceivedInCI(testFile)
cy.contains("how to initialize the test environment").should(
"have.css",
"background-color",
backgroundColors.hovered,
)

// select the other file - the highlight should move to it
cy.typeIntoTerminal(`/^${dir.contents["initial-file.txt"].name}{enter}`, {
delay: 1,
})
cy.contains("how to initialize the test environment").should(
"have.css",
"background-color",
backgroundColors.normal,
)
cy.contains("If you see this text, Neovim is ready!").should(
"have.css",
"background-color",
backgroundColors.hovered,
)
})
})

it("doesn't crash if the user doesn't want to highlight", () => {
// "not wanting to highlight" means that the user hasn't enabled the
// highlight in their YaziConfig. It is acceptable to opt out of using this
// feature, and it shouldn't cause a crash.

// NOTE don't set the startupScriptModifications. This causes the highlight
// to not be enabled in the YaziConfig.
startNeovimWithYa({ startupScriptModifications: [] }).then((dir) => {
// wait until text on the start screen is visible
cy.contains("If you see this text, Neovim is ready!")
.children()
.should("have.css", "background-color", backgroundColors.normal)

// start yazi
cy.typeIntoTerminal("{upArrow}")

hoverAnotherFileToEnsureHoverEventIsReceivedInCI(
dir.contents["test.lua"].name,
)

// yazi is shown and adjacent files should be visible now
//
// highlight the initial file
cy.typeIntoTerminal(`/${dir.contents["initial-file.txt"].name}{enter}`)
cy.contains("Error").should("not.exist")

// no highlight should be visible
cy.contains("If you see this text, Neovim is ready!").should(
"have.css",
"background-color",
backgroundColors.normal,
)
})
})
})
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,17 @@ import type {
TestDirectory,
} from "../../../client/testEnvironmentTypes"

/** NOTE: always uses the `modify_yazi_config_to_use_ya_as_event_reader.lua` as
* that is implied by the name of the function.
*/
export function startNeovimWithYa(
args?: Partial<StartNeovimArguments>,
): Cypress.Chainable<TestDirectory> {
return cy.startNeovim({
...args,
startupScriptModifications: [
"modify_yazi_config_to_use_ya_as_event_reader.lua",
...(args?.startupScriptModifications ?? []),
],
})
}
18 changes: 12 additions & 6 deletions integration-tests/cypress/support/commands.ts
Original file line number Diff line number Diff line change
Expand Up @@ -54,17 +54,23 @@ Cypress.Commands.add("startNeovim", (startArguments?: StartNeovimArguments) => {
})
})

Cypress.Commands.add("typeIntoTerminal", (text: string) => {
// the syntax for keys is described here:
// https://docs.cypress.io/api/commands/type
cy.get("#app").type(text)
})
Cypress.Commands.add(
"typeIntoTerminal",
(text: string, options?: Partial<Cypress.TypeOptions>) => {
// the syntax for keys is described here:
// https://docs.cypress.io/api/commands/type
cy.get("#app").type(text, options)
},
)

declare global {
namespace Cypress {
interface Chainable {
startNeovim(args?: StartNeovimArguments): Chainable<TestDirectory>
typeIntoTerminal(text: string): Chainable<void>
typeIntoTerminal(
text: string,
options?: Partial<Cypress.TypeOptions>,
): Chainable<void>
task(event: "createTempDir"): Chainable<TestDirectory>
}
}
Expand Down
12 changes: 11 additions & 1 deletion integration-tests/server/server.ts
Original file line number Diff line number Diff line change
Expand Up @@ -46,14 +46,24 @@ io.on("connection", function connection(socket) {
switch (modification) {
// execute a lua script after startup, allowing the tests to modify
// the base config without overriding all of it
case "modify_yazi_config_to_use_ya_as_event_reader.lua":
case "modify_yazi_config_to_use_ya_as_event_reader.lua": {
const file = path.join(
testDirectory,
"config-modifications",
"modify_yazi_config_to_use_ya_as_event_reader.lua",
)
args.push("-c", `lua dofile('${file}')`)
break
}
case "modify_yazi_config_and_add_hovered_buffer_background.lua": {
const file = path.join(
testDirectory,
"config-modifications",
"modify_yazi_config_and_add_hovered_buffer_background.lua",
)
args.push("-c", `lua dofile('${file}')`)
break
}
default:
modification satisfies never
throw new Error(
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
---@module "yazi"

require('yazi').setup(
---@type YaziConfig
{
highlight_groups = {
hovered_buffer_background = { bg = '#494d64' },
},
}
)
46 changes: 46 additions & 0 deletions lua/yazi/buffer_highlighting/disposable_highlight.lua
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
local Log = require('yazi.log')

---@class yazi.DisposableHighlight
---@field private old_winhighlight string
---@field private window_id integer
local DisposableHighlight = {}
DisposableHighlight.__index = DisposableHighlight

---@param window_id integer
---@param highlight_config YaziConfigHighlightGroups
function DisposableHighlight.new(window_id, highlight_config)
local self = setmetatable({}, DisposableHighlight)
self.window_id = window_id
self.old_winhighlight = vim.wo.winhighlight

vim.api.nvim_set_hl(
0,
'YaziBufferHoveredBackground',
highlight_config.hovered_buffer_background
)

vim.api.nvim_set_option_value(
'winhighlight',
'Normal:YaziBufferHoveredBackground',
{ win = window_id }
)

return self
end

function DisposableHighlight:dispose()
Log:debug(
string.format(
'Disposing of the DisposableHighlight for window_id %s',
self.window_id
)
)
-- Revert winhighlight to its old value
if vim.api.nvim_win_is_valid(self.window_id) then
vim.api.nvim_set_option_value('winhighlight', self.old_winhighlight, {
win = self.window_id,
})
end
end

return DisposableHighlight
Loading

0 comments on commit b249ec4

Please sign in to comment.