Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: extmark-based placeholder for text inputs #7

Merged
merged 2 commits into from
Apr 1, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
31 changes: 26 additions & 5 deletions docs/pages/docs/components/prompt.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import { Property } from '../../../components/Property'
```lua
n.prompt({
prefix = " > ",
placeholder = "Enter a command",
border_label = {
text = "Command",
align = "center",
Expand All @@ -25,31 +26,51 @@ n.prompt({

#### value

<Property
<Property
types={["string"]}
/>

#### prefix

<Property
<Property
types={["string"]}
/>

#### placeholder

> Optional placeholder text to show when the input is empty.
> Can be a string, a single virtual text chunk, or a list of virtual text chunks.

<Property
defaultValue='nil'
types={['string', '{ [1]: string, [2]: string }[]', 'nil']}
/>

A virtual text chunk is a tuple-like table where the first element
is the text and the second element is the highlight group.

```lua
local placeholder = {
{ "Hello", "Comment" },
{ "World", "String" },
}
```

#### on_change

<Property
<Property
types={['fun(value: string, component: Prompt): nil']}
/>

#### on_submit

<Property
<Property
types={['fun(value: string, component: Prompt): nil']}
/>

#### submit_key

<Property
<Property
defaultValue="<CR>"
types={["string[]", "string"]}
/>
Expand Down
33 changes: 27 additions & 6 deletions docs/pages/docs/components/text-input.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,14 @@ import { Property } from '../../../components/Property'

## TextInput

`TextInput` is a component that allows you to enter any text.
`TextInput` is a component that allows you to enter any text.

![](/gifs/text-input-1.gif)

### Usage Example

```lua
local signal = n.create_signal({
local signal = n.create_signal({
value = "hello world",
})

Expand All @@ -20,6 +20,7 @@ n.text_input({
size = 1,
value = signal.value,
border_label = "Description",
placeholder = "Enter a description",
max_lines = 5,
on_change = function(value, component)
signal.value = value
Expand All @@ -38,7 +39,7 @@ n.text_input({

### Properties

#### autoresize
#### autoresize

<Property
defaultValue="false"
Expand All @@ -47,20 +48,40 @@ n.text_input({

#### max_lines

<Property
<Property
types={['number']}
/>

#### value

<Property
<Property
defaultValue='""'
types={['string']}
/>

#### placeholder

> Optional placeholder text to show when the input is empty.
> Can be a string, a single virtual text chunk, or a list of virtual text chunks.

<Property
defaultValue='nil'
types={['string', '{ [1]: string, [2]: string }[]', 'nil']}
/>

A virtual text chunk is a tuple-like table where the first element
is the text and the second element is the highlight group.

```lua
local placeholder = {
{ "Hello", "Comment" },
{ "World", "String" },
}
```

#### on_change

<Property
<Property
types={['fun(value: string, component: TextInput): nil']}
/>

2 changes: 2 additions & 0 deletions lua/nui-components/prompt.lua
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,8 @@ function Prompt:_attach_change_listener()
self:set_current_value(value)
props.on_change(value, self)

self:_update_placeholder()

if prefix_length > 0 then
vim.schedule(function()
self._private.prefix:highlight(self.bufnr, self.ns_id, 1, 0)
Expand Down
34 changes: 34 additions & 0 deletions lua/nui-components/text-input.lua
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ function TextInput:init(props, popup_options)
autoresize = false,
max_lines = nil,
value = "",
placeholder = "",
on_change = fn.ignore,
border_style = "rounded",
}, props)
Expand Down Expand Up @@ -52,9 +53,39 @@ function TextInput:prop_types()
autoresize = { "boolean", "nil" },
wrap = { "boolean", "nil" },
filetype = { "string", "nil" },
placeholder = { "string", "table", "nil" },
}
end

function TextInput:_update_placeholder()
local show = self:get_current_value() == ""
local props = self:get_props()
local placeholder = props.placeholder
if show and placeholder and placeholder ~= "" then
local virt_text
if type(placeholder) == "table" then
if type(placeholder[1]) == "table" then
-- multiple virt-text chunks
virt_text = placeholder
else
-- single virt-text chunk
virt_text = { placeholder }
end
else
-- string
virt_text = { { placeholder, "Comment" } }
end
self._private.placeholder_extmark = vim.api.nvim_buf_set_extmark(self.bufnr, self.ns_id, 0, 0, {
virt_text = virt_text,
virt_text_pos = "inline",
id = self._private.placeholder_extmark,
})
elseif self._private.placeholder_extmark then
vim.api.nvim_buf_del_extmark(self.bufnr, self.ns_id, self._private.placeholder_extmark)
self._private.placeholder_extmark = nil
end
end

function TextInput:_attach_change_listener()
local props = self:get_props()

Expand All @@ -66,6 +97,8 @@ function TextInput:_attach_change_listener()
self:set_current_value(value)
props.on_change(value, self)

self:_update_placeholder()

if props.autoresize then
self._private.text_input_signal.size = math.max(#lines, self._private.text_input_initial_size)
end
Expand Down Expand Up @@ -184,6 +217,7 @@ end

function TextInput:on_mount()
self:_attach_change_listener()
self:_update_placeholder()
end

return TextInput
Loading