We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
Python error after pressing SPACE to pull up command-name input
**Small description**
The first time I press SPACE on a sheet, I often get the following Python error. It usually succeeds on the second press.

**Expected result**
Open command prompt.

**Actual result with screenshot**
![Screenshot from 2024-03-03 15-07-48](https://github.com/saulpw/visidata/assets/6864226/e9245111-df2d-4958-97be-66c5abcfb9ec)
[errors_recent.txt](https://github.com/saulpw/visidata/files/14471969/errors_recent.txt)

**Steps to reproduce with sample data and a .vd**
Open any sheet and press SPACE.
It may take a few attempts. It seems to only happen the first time it is entered on a sheet, and only some of the time.

**Additional context**
Python 3.8.0
VisiData 3.0.2


--- END ISSUE ---

Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
--- BEGIN FILES ---
Path: `visidata/features/cmdpalette.py`
Content:
```
1 import collections
2 from functools import partial
3 from visidata import DrawablePane, BaseSheet, vd, VisiData, CompleteKey, clipdraw, HelpSheet, colors, AcceptInput, AttrDict, drawcache_property
4 
5 
6 vd.theme_option('color_cmdpalette', 'black on 72', 'base color of command palette')
7 vd.theme_option('disp_cmdpal_max', 10, 'max number of suggestions for command palette')
8 
9 vd.help_longname = '''# Choose Command
10 Start typing a command longname or keyword in its helpstring.
11 
12 - `Enter` to execute top command.
13 - `Tab` to highlight top command.
14 
15 ## When Command Highlighted
16 
17 - `Tab`/`Shift+Tab` to cycle highlighted command.
18 - `Enter` to execute highlighted command.
19 - `0-9` to execute numbered command.
20 '''
21 
22 def add_to_input(v, i, value=''):
23     items = list(v.split())
24     if not v or v.endswith(' '):
25         items.append(value)
26     else:
27         items[-1] = value
28     v = ' '.join(items) + ' '
29     return v, len(v)
30 
31 
32 def accept_input(v, i, value=None):
33     raise AcceptInput(v if value is None else value)
34 
35 def accept_input_if_subset(v, i, value=''):
36     # if no input, accept value under cmd palette cursor
37     if not v:
38         raise AcceptInput(value)
39 
40     # if the last item is a partial match, replace it with the full value
41     parts = v.split()
42     if value and value.startswith(parts[-1]):
43         v = ' '.join(parts[:-1] + [value])
44 
45     raise AcceptInput(v)
46 
47 @VisiData.lazy_property
48 def usedInputs(vd):
49     return collections.defaultdict(int)
50 
51 @DrawablePane.after
52 def execCommand2(sheet, cmd, *args, **kwargs):
53     vd.usedInputs[cmd.longname] += 1
54 
55 @BaseSheet.api
56 def inputPalette(sheet, prompt, items,
57                  value_key='key',
58                  formatter=lambda m, item, trigger_key: f'{trigger_key} {item}',
59                  multiple=False,
60                  **kwargs):
61     bindings = dict()
62 
63     tabitem = -1
64 
65     def tab(n, nitems):
66         nonlocal tabitem
67         if not nitems: return None
68         tabitem = (tabitem + n) % nitems
69 
70     def _draw_palette(value):
71         words = value.lower().split()
72 
73         if multiple and words:
74             if value.endswith(' '):
75                 finished_words = words
76                 unfinished_words = []
77             else:
78                 finished_words = words[:-1]
79                 unfinished_words = [words[-1]]
80         else:
81             unfinished_words = words
82             finished_words = []
83 
84         unuseditems = [item for item in items if item[value_key] not in finished_words]
85 
86         matches = vd.fuzzymatch(unuseditems, unfinished_words)
87 
88         h = sheet.windowHeight
89         w = min(100, sheet.windowWidth)
90         nitems = min(h-1, sheet.options.disp_cmdpal_max)
91 
92         useditems = []
93         palrows = []
94 
95         for m in matches[:nitems]:
96             useditems.append(m.match)
97             palrows.append((m, m.match))
98 
99         favitems = sorted([item for item in unuseditems if item not in useditems],
100                           key=lambda item: -vd.usedInputs.get(item[value_key], 0))
101 
102         for item in favitems[:nitems-len(palrows)]:
103             palrows.append((None, item))
104 
105         navailitems = min(len(palrows), nitems)
106 
107         bindings['^I'] = lambda *args: tab(1, navailitems) or args
108         bindings['KEY_BTAB'] = lambda *args: tab(-1, navailitems) or args
109 
110         for i in range(nitems-len(palrows)):
111             palrows.append((None, None))
112 
113         used_triggers = set()
114         for i, (m, item) in enumerate(palrows):
115             trigger_key = ''
116             if tabitem >= 0 and item:
117                 tkey = f'{i+1}'[-1]
118                 if tkey not in used_triggers:
119                     trigger_key = tkey
120                     bindings[trigger_key] = partial(add_to_input if multiple else accept_input, value=item[value_key])
121                     used_triggers.add(trigger_key)
122 
123             attr = colors.color_cmdpalette
124 
125             if tabitem < 0 and palrows:
126                 _ , topitem = palrows[0]
127                 if not topitem: return
128                 if multiple:
129                     bindings[' '] = partial(add_to_input, value=topitem[value_key])
130                     bindings['^J'] = partial(accept_input_if_subset, value=topitem[value_key])
131                 else:
132                     bindings['^J'] = partial(accept_input, value=topitem[value_key])
133             elif item and i == tabitem:
134                 if not item: return
135                 if multiple:
136                     bindings['^J'] = partial(accept_input_if_subset, value=item[value_key])
137                     bindings[' '] = partial(add_to_input, value=item[value_key])
138                 else:
139                     bindings['^J'] = partial(accept_input, value=item[value_key])
140                 attr = colors.color_menu_spec
141 
142             match_summary = formatter(m, item, trigger_key) if item else ' '
143 
144             clipdraw(sheet._scr, h-nitems-1+i, 0, match_summary, attr, w=w)
145 
146         return None
147 
148     completer = CompleteKey(sorted(item[value_key] for item in items))
149     return vd.input(prompt,
150             completer=completer,
151             updater=_draw_palette,
152             bindings=bindings,
153             **kwargs)
154 
155 
156 def cmdlist(sheet):
157     return [
158             AttrDict(longname=row.longname,
159                      description=sheet.cmddict[(row.sheet, row.longname)].helpstr)
160         for row in sheet.rows
161     ]
162 HelpSheet.cmdlist = drawcache_property(cmdlist)
163 
164 
165 @BaseSheet.api
166 def inputLongname(sheet):
167     prompt = 'command name: '
168     # get set of commands possible in the sheet
169     this_sheets_help = HelpSheet('', source=sheet)
170     this_sheets_help.ensureLoaded()
171 
172     def _fmt_cmdpal_summary(match, row, trigger_key):
173         keystrokes = this_sheets_help.revbinds.get(row.longname, [None])[0] or ' '
174         formatted_longname = match.formatted.get('longname', row.longname) if match else row.longname
175         formatted_name = f'[:bold][:onclick {row.longname}]{formatted_longname}[/][/]'
176         if vd.options.debug and match:
177             keystrokes = f'[{match.score}]'
178         r = f' [:keystrokes]{keystrokes.rjust(len(prompt)-5)}[/]  '
179         if trigger_key:
180             r += f'[:keystrokes]{trigger_key}[/]'
181         else:
182             r += ' '
183 
184         r += f' {formatted_name}'
185         if row.description:
186             formatted_desc = match.formatted.get('description', row.description) if match else row.description
187             r += f' - {formatted_desc}'
188         return r
189 
190     return sheet.inputPalette(prompt, this_sheets_help.cmdlist,
191                               value_key='longname',
192                               formatter=_fmt_cmdpal_summary,
193                               help=vd.help_longname,
194                               type='longname')
195 
196 
197 @BaseSheet.api
198 def exec_longname(sheet, longname):
199     if not sheet.getCommand(longname):
200         vd.fail(f'no command {longname}')
201     sheet.execCommand(longname)
202 
203 
204 vd.addCommand('Space', 'exec-longname', 'exec_longname(inputLongname())', 'execute command by its longname')
205
```
--- END FILES ---

Please first localize the bug based on the issue statement, and then generate a patch according to the `git diff` format fenced by three backticks.

Here is an example:

```diff
diff --git a/examples/server_async.py b/examples/server_async.py
--- a/examples/server_async.py
+++ b/examples/server_async.py
@@ -313,4 +313,4 @@
 
 
 if __name__ == "__main__":
-    asyncio.run(run_async_server("."), debug=True)
+    asyncio.run(run_async_server(), debug=True)
diff --git a/examples/server_sync.py b/examples/server_sync.py
--- a/examples/server_sync.py
+++ b/examples/server_sync.py
@@ -313,5 +313,5 @@
 
 
 if __name__ == "__main__":
-    server = run_sync_server(".")
+    server = run_sync_server()
     server.shutdown()

```

diff --git a/visidata/features/cmdpalette.py b/visidata/features/cmdpalette.py
--- a/visidata/features/cmdpalette.py
+++ b/visidata/features/cmdpalette.py
@@ -167,7 +167,7 @@
     prompt = 'command name: '
     # get set of commands possible in the sheet
     this_sheets_help = HelpSheet('', source=sheet)
-    this_sheets_help.ensureLoaded()
+    vd.sync(this_sheets_help.ensureLoaded())
 
     def _fmt_cmdpal_summary(match, row, trigger_key):
         keystrokes = this_sheets_help.revbinds.get(row.longname, [None])[0] or ' '

{"golden_diff": "diff --git a/visidata/features/cmdpalette.py b/visidata/features/cmdpalette.py\n--- a/visidata/features/cmdpalette.py\n+++ b/visidata/features/cmdpalette.py\n@@ -167,7 +167,7 @@\n     prompt = 'command name: '\n     # get set of commands possible in the sheet\n     this_sheets_help = HelpSheet('', source=sheet)\n-    this_sheets_help.ensureLoaded()\n+    vd.sync(this_sheets_help.ensureLoaded())\n \n     def _fmt_cmdpal_summary(match, row, trigger_key):\n         keystrokes = this_sheets_help.revbinds.get(row.longname, [None])[0] or ' '\n", "issue": "Python error after pressing SPACE to pull up command-name input\n**Small description**\r\nThe first time I press SPACE on a sheet, I often get the following Python error. It usually succeeds on the second press.\r\n\r\n**Expected result**\r\nOpen command prompt.\r\n\r\n**Actual result with screenshot**\r\n![Screenshot from 2024-03-03 15-07-48](https://github.com/saulpw/visidata/assets/6864226/e9245111-df2d-4958-97be-66c5abcfb9ec)\r\n[errors_recent.txt](https://github.com/saulpw/visidata/files/14471969/errors_recent.txt)\r\n\r\n**Steps to reproduce with sample data and a .vd**\r\nOpen any sheet and press SPACE.\r\nIt may take a few attempts. It seems to only happen the first time it is entered on a sheet, and only some of the time.\r\n\r\n**Additional context**\r\nPython 3.8.0\r\nVisiData 3.0.2\r\n\n", "before_files": [{"content": "import collections\nfrom functools import partial\nfrom visidata import DrawablePane, BaseSheet, vd, VisiData, CompleteKey, clipdraw, HelpSheet, colors, AcceptInput, AttrDict, drawcache_property\n\n\nvd.theme_option('color_cmdpalette', 'black on 72', 'base color of command palette')\nvd.theme_option('disp_cmdpal_max', 10, 'max number of suggestions for command palette')\n\nvd.help_longname = '''# Choose Command\nStart typing a command longname or keyword in its helpstring.\n\n- `Enter` to execute top command.\n- `Tab` to highlight top command.\n\n## When Command Highlighted\n\n- `Tab`/`Shift+Tab` to cycle highlighted command.\n- `Enter` to execute highlighted command.\n- `0-9` to execute numbered command.\n'''\n\ndef add_to_input(v, i, value=''):\n    items = list(v.split())\n    if not v or v.endswith(' '):\n        items.append(value)\n    else:\n        items[-1] = value\n    v = ' '.join(items) + ' '\n    return v, len(v)\n\n\ndef accept_input(v, i, value=None):\n    raise AcceptInput(v if value is None else value)\n\ndef accept_input_if_subset(v, i, value=''):\n    # if no input, accept value under cmd palette cursor\n    if not v:\n        raise AcceptInput(value)\n\n    # if the last item is a partial match, replace it with the full value\n    parts = v.split()\n    if value and value.startswith(parts[-1]):\n        v = ' '.join(parts[:-1] + [value])\n\n    raise AcceptInput(v)\n\n@VisiData.lazy_property\ndef usedInputs(vd):\n    return collections.defaultdict(int)\n\n@DrawablePane.after\ndef execCommand2(sheet, cmd, *args, **kwargs):\n    vd.usedInputs[cmd.longname] += 1\n\n@BaseSheet.api\ndef inputPalette(sheet, prompt, items,\n                 value_key='key',\n                 formatter=lambda m, item, trigger_key: f'{trigger_key} {item}',\n                 multiple=False,\n                 **kwargs):\n    bindings = dict()\n\n    tabitem = -1\n\n    def tab(n, nitems):\n        nonlocal tabitem\n        if not nitems: return None\n        tabitem = (tabitem + n) % nitems\n\n    def _draw_palette(value):\n        words = value.lower().split()\n\n        if multiple and words:\n            if value.endswith(' '):\n                finished_words = words\n                unfinished_words = []\n            else:\n                finished_words = words[:-1]\n                unfinished_words = [words[-1]]\n        else:\n            unfinished_words = words\n            finished_words = []\n\n        unuseditems = [item for item in items if item[value_key] not in finished_words]\n\n        matches = vd.fuzzymatch(unuseditems, unfinished_words)\n\n        h = sheet.windowHeight\n        w = min(100, sheet.windowWidth)\n        nitems = min(h-1, sheet.options.disp_cmdpal_max)\n\n        useditems = []\n        palrows = []\n\n        for m in matches[:nitems]:\n            useditems.append(m.match)\n            palrows.append((m, m.match))\n\n        favitems = sorted([item for item in unuseditems if item not in useditems],\n                          key=lambda item: -vd.usedInputs.get(item[value_key], 0))\n\n        for item in favitems[:nitems-len(palrows)]:\n            palrows.append((None, item))\n\n        navailitems = min(len(palrows), nitems)\n\n        bindings['^I'] = lambda *args: tab(1, navailitems) or args\n        bindings['KEY_BTAB'] = lambda *args: tab(-1, navailitems) or args\n\n        for i in range(nitems-len(palrows)):\n            palrows.append((None, None))\n\n        used_triggers = set()\n        for i, (m, item) in enumerate(palrows):\n            trigger_key = ''\n            if tabitem >= 0 and item:\n                tkey = f'{i+1}'[-1]\n                if tkey not in used_triggers:\n                    trigger_key = tkey\n                    bindings[trigger_key] = partial(add_to_input if multiple else accept_input, value=item[value_key])\n                    used_triggers.add(trigger_key)\n\n            attr = colors.color_cmdpalette\n\n            if tabitem < 0 and palrows:\n                _ , topitem = palrows[0]\n                if not topitem: return\n                if multiple:\n                    bindings[' '] = partial(add_to_input, value=topitem[value_key])\n                    bindings['^J'] = partial(accept_input_if_subset, value=topitem[value_key])\n                else:\n                    bindings['^J'] = partial(accept_input, value=topitem[value_key])\n            elif item and i == tabitem:\n                if not item: return\n                if multiple:\n                    bindings['^J'] = partial(accept_input_if_subset, value=item[value_key])\n                    bindings[' '] = partial(add_to_input, value=item[value_key])\n                else:\n                    bindings['^J'] = partial(accept_input, value=item[value_key])\n                attr = colors.color_menu_spec\n\n            match_summary = formatter(m, item, trigger_key) if item else ' '\n\n            clipdraw(sheet._scr, h-nitems-1+i, 0, match_summary, attr, w=w)\n\n        return None\n\n    completer = CompleteKey(sorted(item[value_key] for item in items))\n    return vd.input(prompt,\n            completer=completer,\n            updater=_draw_palette,\n            bindings=bindings,\n            **kwargs)\n\n\ndef cmdlist(sheet):\n    return [\n            AttrDict(longname=row.longname,\n                     description=sheet.cmddict[(row.sheet, row.longname)].helpstr)\n        for row in sheet.rows\n    ]\nHelpSheet.cmdlist = drawcache_property(cmdlist)\n\n\n@BaseSheet.api\ndef inputLongname(sheet):\n    prompt = 'command name: '\n    # get set of commands possible in the sheet\n    this_sheets_help = HelpSheet('', source=sheet)\n    this_sheets_help.ensureLoaded()\n\n    def _fmt_cmdpal_summary(match, row, trigger_key):\n        keystrokes = this_sheets_help.revbinds.get(row.longname, [None])[0] or ' '\n        formatted_longname = match.formatted.get('longname', row.longname) if match else row.longname\n        formatted_name = f'[:bold][:onclick {row.longname}]{formatted_longname}[/][/]'\n        if vd.options.debug and match:\n            keystrokes = f'[{match.score}]'\n        r = f' [:keystrokes]{keystrokes.rjust(len(prompt)-5)}[/]  '\n        if trigger_key:\n            r += f'[:keystrokes]{trigger_key}[/]'\n        else:\n            r += ' '\n\n        r += f' {formatted_name}'\n        if row.description:\n            formatted_desc = match.formatted.get('description', row.description) if match else row.description\n            r += f' - {formatted_desc}'\n        return r\n\n    return sheet.inputPalette(prompt, this_sheets_help.cmdlist,\n                              value_key='longname',\n                              formatter=_fmt_cmdpal_summary,\n                              help=vd.help_longname,\n                              type='longname')\n\n\n@BaseSheet.api\ndef exec_longname(sheet, longname):\n    if not sheet.getCommand(longname):\n        vd.fail(f'no command {longname}')\n    sheet.execCommand(longname)\n\n\nvd.addCommand('Space', 'exec-longname', 'exec_longname(inputLongname())', 'execute command by its longname')\n", "path": "visidata/features/cmdpalette.py"}], "after_files": [{"content": "import collections\nfrom functools import partial\nfrom visidata import DrawablePane, BaseSheet, vd, VisiData, CompleteKey, clipdraw, HelpSheet, colors, AcceptInput, AttrDict, drawcache_property\n\n\nvd.theme_option('color_cmdpalette', 'black on 72', 'base color of command palette')\nvd.theme_option('disp_cmdpal_max', 10, 'max number of suggestions for command palette')\n\nvd.help_longname = '''# Choose Command\nStart typing a command longname or keyword in its helpstring.\n\n- `Enter` to execute top command.\n- `Tab` to highlight top command.\n\n## When Command Highlighted\n\n- `Tab`/`Shift+Tab` to cycle highlighted command.\n- `Enter` to execute highlighted command.\n- `0-9` to execute numbered command.\n'''\n\ndef add_to_input(v, i, value=''):\n    items = list(v.split())\n    if not v or v.endswith(' '):\n        items.append(value)\n    else:\n        items[-1] = value\n    v = ' '.join(items) + ' '\n    return v, len(v)\n\n\ndef accept_input(v, i, value=None):\n    raise AcceptInput(v if value is None else value)\n\ndef accept_input_if_subset(v, i, value=''):\n    # if no input, accept value under cmd palette cursor\n    if not v:\n        raise AcceptInput(value)\n\n    # if the last item is a partial match, replace it with the full value\n    parts = v.split()\n    if value and value.startswith(parts[-1]):\n        v = ' '.join(parts[:-1] + [value])\n\n    raise AcceptInput(v)\n\n@VisiData.lazy_property\ndef usedInputs(vd):\n    return collections.defaultdict(int)\n\n@DrawablePane.after\ndef execCommand2(sheet, cmd, *args, **kwargs):\n    vd.usedInputs[cmd.longname] += 1\n\n@BaseSheet.api\ndef inputPalette(sheet, prompt, items,\n                 value_key='key',\n                 formatter=lambda m, item, trigger_key: f'{trigger_key} {item}',\n                 multiple=False,\n                 **kwargs):\n    bindings = dict()\n\n    tabitem = -1\n\n    def tab(n, nitems):\n        nonlocal tabitem\n        if not nitems: return None\n        tabitem = (tabitem + n) % nitems\n\n    def _draw_palette(value):\n        words = value.lower().split()\n\n        if multiple and words:\n            if value.endswith(' '):\n                finished_words = words\n                unfinished_words = []\n            else:\n                finished_words = words[:-1]\n                unfinished_words = [words[-1]]\n        else:\n            unfinished_words = words\n            finished_words = []\n\n        unuseditems = [item for item in items if item[value_key] not in finished_words]\n\n        matches = vd.fuzzymatch(unuseditems, unfinished_words)\n\n        h = sheet.windowHeight\n        w = min(100, sheet.windowWidth)\n        nitems = min(h-1, sheet.options.disp_cmdpal_max)\n\n        useditems = []\n        palrows = []\n\n        for m in matches[:nitems]:\n            useditems.append(m.match)\n            palrows.append((m, m.match))\n\n        favitems = sorted([item for item in unuseditems if item not in useditems],\n                          key=lambda item: -vd.usedInputs.get(item[value_key], 0))\n\n        for item in favitems[:nitems-len(palrows)]:\n            palrows.append((None, item))\n\n        navailitems = min(len(palrows), nitems)\n\n        bindings['^I'] = lambda *args: tab(1, navailitems) or args\n        bindings['KEY_BTAB'] = lambda *args: tab(-1, navailitems) or args\n\n        for i in range(nitems-len(palrows)):\n            palrows.append((None, None))\n\n        used_triggers = set()\n        for i, (m, item) in enumerate(palrows):\n            trigger_key = ''\n            if tabitem >= 0 and item:\n                tkey = f'{i+1}'[-1]\n                if tkey not in used_triggers:\n                    trigger_key = tkey\n                    bindings[trigger_key] = partial(add_to_input if multiple else accept_input, value=item[value_key])\n                    used_triggers.add(trigger_key)\n\n            attr = colors.color_cmdpalette\n\n            if tabitem < 0 and palrows:\n                _ , topitem = palrows[0]\n                if not topitem: return\n                if multiple:\n                    bindings[' '] = partial(add_to_input, value=topitem[value_key])\n                    bindings['^J'] = partial(accept_input_if_subset, value=topitem[value_key])\n                else:\n                    bindings['^J'] = partial(accept_input, value=topitem[value_key])\n            elif item and i == tabitem:\n                if not item: return\n                if multiple:\n                    bindings['^J'] = partial(accept_input_if_subset, value=item[value_key])\n                    bindings[' '] = partial(add_to_input, value=item[value_key])\n                else:\n                    bindings['^J'] = partial(accept_input, value=item[value_key])\n                attr = colors.color_menu_spec\n\n            match_summary = formatter(m, item, trigger_key) if item else ' '\n\n            clipdraw(sheet._scr, h-nitems-1+i, 0, match_summary, attr, w=w)\n\n        return None\n\n    completer = CompleteKey(sorted(item[value_key] for item in items))\n    return vd.input(prompt,\n            completer=completer,\n            updater=_draw_palette,\n            bindings=bindings,\n            **kwargs)\n\n\ndef cmdlist(sheet):\n    return [\n            AttrDict(longname=row.longname,\n                     description=sheet.cmddict[(row.sheet, row.longname)].helpstr)\n        for row in sheet.rows\n    ]\nHelpSheet.cmdlist = drawcache_property(cmdlist)\n\n\n@BaseSheet.api\ndef inputLongname(sheet):\n    prompt = 'command name: '\n    # get set of commands possible in the sheet\n    this_sheets_help = HelpSheet('', source=sheet)\n    vd.sync(this_sheets_help.ensureLoaded())\n\n    def _fmt_cmdpal_summary(match, row, trigger_key):\n        keystrokes = this_sheets_help.revbinds.get(row.longname, [None])[0] or ' '\n        formatted_longname = match.formatted.get('longname', row.longname) if match else row.longname\n        formatted_name = f'[:bold][:onclick {row.longname}]{formatted_longname}[/][/]'\n        if vd.options.debug and match:\n            keystrokes = f'[{match.score}]'\n        r = f' [:keystrokes]{keystrokes.rjust(len(prompt)-5)}[/]  '\n        if trigger_key:\n            r += f'[:keystrokes]{trigger_key}[/]'\n        else:\n            r += ' '\n\n        r += f' {formatted_name}'\n        if row.description:\n            formatted_desc = match.formatted.get('description', row.description) if match else row.description\n            r += f' - {formatted_desc}'\n        return r\n\n    return sheet.inputPalette(prompt, this_sheets_help.cmdlist,\n                              value_key='longname',\n                              formatter=_fmt_cmdpal_summary,\n                              help=vd.help_longname,\n                              type='longname')\n\n\n@BaseSheet.api\ndef exec_longname(sheet, longname):\n    if not sheet.getCommand(longname):\n        vd.fail(f'no command {longname}')\n    sheet.execCommand(longname)\n\n\nvd.addCommand('Space', 'exec-longname', 'exec_longname(inputLongname())', 'execute command by its longname')\n", "path": "visidata/features/cmdpalette.py"}]}