Skip to content

Commit

Permalink
Merge pull request #7 from willothy/input-placeholder
Browse files Browse the repository at this point in the history
feat: extmark-based placeholder for text inputs
  • Loading branch information
mobily authored Apr 1, 2024
2 parents 6202be4 + 2d8ec98 commit 67b38d3
Show file tree
Hide file tree
Showing 4 changed files with 89 additions and 11 deletions.
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

0 comments on commit 67b38d3

Please sign in to comment.