prompt: We are currently solving the following issue within our repository. Here is the issue text:
  --- BEGIN ISSUE ---
  [zo] Give feedback when a file or URL is not found in the cell value
  New users (and me when I have a few z related `open-cell-XYZ` commands 🙃) may get confused at the purpose of `zo`, when it is usually `zENTER` they want.
  
  I propose the change, whereby a status is given to the user to tell them that a `file` or `URL` wasn't found (and therefore nothing happens). Also maybe suggest they want `zENTER`?
  
  --- 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/_open.py`
  Content:
  ```
  1 from visidata import *
  2 
  3 
  4 vd.option('filetype', '', 'specify file type', replay=True)
  5 
  6 
  7 @VisiData.api
  8 def inputFilename(vd, prompt, *args, **kwargs):
  9     return vd.input(prompt, type="filename", *args, completer=_completeFilename, **kwargs).strip()
  10 
  11 
  12 @VisiData.api
  13 def inputPath(vd, *args, **kwargs):
  14     return Path(vd.inputFilename(*args, **kwargs))
  15 
  16 
  17 def _completeFilename(val, state):
  18     i = val.rfind('/')
  19     if i < 0:  # no /
  20         base = ''
  21         partial = val
  22     elif i == 0: # root /
  23         base = '/'
  24         partial = val[1:]
  25     else:
  26         base = val[:i]
  27         partial = val[i+1:]
  28 
  29     files = []
  30     for f in os.listdir(Path(base or '.')):
  31         if f.startswith(partial):
  32             files.append(os.path.join(base, f))
  33 
  34     files.sort()
  35     return files[state%len(files)]
  36 
  37 
  38 @VisiData.api
  39 def openPath(vd, p, filetype=None, create=False):
  40     '''Call ``open_<filetype>(p)`` or ``openurl_<p.scheme>(p, filetype)``.  Return constructed but unloaded sheet of appropriate type.
  41     If True, *create* will return a new, blank **Sheet** if file does not exist.'''
  42     if p.scheme and not p.has_fp():
  43         schemes = p.scheme.split('+')
  44         openfuncname = 'openurl_' + schemes[-1]
  45 
  46         openfunc = getattr(vd, openfuncname, None) or vd.getGlobals().get(openfuncname, None)
  47         if not openfunc:
  48             vd.fail(f'no loader for url scheme: {p.scheme}')
  49 
  50         return openfunc(p, filetype=filetype)
  51 
  52     if not p.exists() and not create:
  53         return None
  54 
  55     if not filetype:
  56         if p.is_dir():
  57             filetype = 'dir'
  58         else:
  59             filetype = p.ext or options.filetype or 'txt'
  60 
  61     filetype = filetype.lower()
  62 
  63     if not p.exists():
  64         if not create:
  65             return None
  66         newfunc = getattr(vd, 'new_' + filetype, vd.getGlobals().get('new_' + filetype))
  67         if not newfunc:
  68             vd.warning('%s does not exist, creating new sheet' % p)
  69             return vd.newSheet(p.name, 1, source=p)
  70 
  71         vd.status('creating blank %s' % (p.given))
  72         return newfunc(p)
  73 
  74     openfunc = getattr(vd, 'open_' + filetype, vd.getGlobals().get('open_' + filetype))
  75     if not openfunc:
  76         vd.warning('unknown "%s" filetype' % filetype)
  77         filetype = 'txt'
  78         openfunc = vd.open_txt
  79 
  80     vd.status('opening %s as %s' % (p.given, filetype))
  81 
  82     return openfunc(p)
  83 
  84 
  85 @VisiData.api
  86 def openSource(vd, p, filetype=None, create=False, **kwargs):
  87     '''Return unloaded sheet object for *p* opened as the given *filetype* and with *kwargs* as option overrides. *p* can be a Path or a string (filename, url, or "-" for stdin).
  88     when true, *create* will return a blank sheet, if file does not exist.'''
  89     if not filetype:
  90         filetype = options.getonly('filetype', 'global', '')
  91 
  92     vs = None
  93     if isinstance(p, str):
  94         if '://' in p:
  95             vs = vd.openPath(Path(p), filetype=filetype)  # convert to Path and recurse
  96         elif p == '-':
  97             vs = vd.openPath(vd.stdinSource, filetype=filetype)
  98         else:
  99             vs = vd.openPath(Path(p), filetype=filetype, create=create)  # convert to Path and recurse
  100     else:
  101         vs = vd.openPath(p, filetype=filetype, create=create)
  102 
  103     for optname, optval in kwargs.items():
  104         vs.options[optname] = optval
  105 
  106     return vs
  107 
  108 
  109 #### enable external addons
  110 @VisiData.api
  111 def open_txt(vd, p):
  112     'Create sheet from `.txt` file at Path `p`, checking whether it is TSV.'
  113     with p.open_text(encoding=vd.options.encoding) as fp:
  114         try:
  115             if options.delimiter in next(fp):    # peek at the first line
  116                 return vd.open_tsv(p)  # TSV often have .txt extension
  117         except StopIteration:
  118             return Sheet(p.name, columns=[SettableColumn()], source=p)
  119         return TextSheet(p.name, source=p)
  120 
  121 
  122 @VisiData.api
  123 def loadInternalSheet(vd, cls, p, **kwargs):
  124     'Load internal sheet of given class.  Internal sheets are always tsv.'
  125     vs = cls(p.name, source=p, **kwargs)
  126     options._set('encoding', 'utf8', vs)
  127     if p.exists():
  128         vd.sheets.insert(0, vs)
  129         vs.reload.__wrapped__(vs)
  130         vd.sheets.pop(0)
  131     return vs
  132 
  133 
  134 BaseSheet.addCommand('o', 'open-file', 'vd.push(openSource(inputFilename("open: "), create=True))', 'Open file or URL')
  135 TableSheet.addCommand('zo', 'open-cell-file', 'vd.push(openSource(cursorDisplay))', 'Open file or URL from path in current cell')
  136
  ```
  --- 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()
  
  ```
  
golden_diff: diff --git a/visidata/_open.py b/visidata/_open.py
  --- a/visidata/_open.py
  +++ b/visidata/_open.py
  @@ -132,4 +132,4 @@
   
   
   BaseSheet.addCommand('o', 'open-file', 'vd.push(openSource(inputFilename("open: "), create=True))', 'Open file or URL')
  -TableSheet.addCommand('zo', 'open-cell-file', 'vd.push(openSource(cursorDisplay))', 'Open file or URL from path in current cell')
  +TableSheet.addCommand('zo', 'open-cell-file', 'vd.push(openSource(cursorDisplay) or fail(f"file {cursorDisplay} does not exist"))', 'Open file or URL from path in current cell')
  
verification_info: {"golden_diff": "diff --git a/visidata/_open.py b/visidata/_open.py\n--- a/visidata/_open.py\n+++ b/visidata/_open.py\n@@ -132,4 +132,4 @@\n \n \n BaseSheet.addCommand('o', 'open-file', 'vd.push(openSource(inputFilename(\"open: \"), create=True))', 'Open file or URL')\n-TableSheet.addCommand('zo', 'open-cell-file', 'vd.push(openSource(cursorDisplay))', 'Open file or URL from path in current cell')\n+TableSheet.addCommand('zo', 'open-cell-file', 'vd.push(openSource(cursorDisplay) or fail(f\"file {cursorDisplay} does not exist\"))', 'Open file or URL from path in current cell')\n", "issue": "[zo] Give feedback when a file or URL is not found in the cell value\nNew users (and me when I have a few z related `open-cell-XYZ` commands \ud83d\ude43) may get confused at the purpose of `zo`, when it is usually `zENTER` they want.\r\n\r\nI propose the change, whereby a status is given to the user to tell them that a `file` or `URL` wasn't found (and therefore nothing happens). Also maybe suggest they want `zENTER`?\n", "before_files": [{"content": "from visidata import *\n\n\nvd.option('filetype', '', 'specify file type', replay=True)\n\n\n@VisiData.api\ndef inputFilename(vd, prompt, *args, **kwargs):\n    return vd.input(prompt, type=\"filename\", *args, completer=_completeFilename, **kwargs).strip()\n\n\n@VisiData.api\ndef inputPath(vd, *args, **kwargs):\n    return Path(vd.inputFilename(*args, **kwargs))\n\n\ndef _completeFilename(val, state):\n    i = val.rfind('/')\n    if i < 0:  # no /\n        base = ''\n        partial = val\n    elif i == 0: # root /\n        base = '/'\n        partial = val[1:]\n    else:\n        base = val[:i]\n        partial = val[i+1:]\n\n    files = []\n    for f in os.listdir(Path(base or '.')):\n        if f.startswith(partial):\n            files.append(os.path.join(base, f))\n\n    files.sort()\n    return files[state%len(files)]\n\n\n@VisiData.api\ndef openPath(vd, p, filetype=None, create=False):\n    '''Call ``open_<filetype>(p)`` or ``openurl_<p.scheme>(p, filetype)``.  Return constructed but unloaded sheet of appropriate type.\n    If True, *create* will return a new, blank **Sheet** if file does not exist.'''\n    if p.scheme and not p.has_fp():\n        schemes = p.scheme.split('+')\n        openfuncname = 'openurl_' + schemes[-1]\n\n        openfunc = getattr(vd, openfuncname, None) or vd.getGlobals().get(openfuncname, None)\n        if not openfunc:\n            vd.fail(f'no loader for url scheme: {p.scheme}')\n\n        return openfunc(p, filetype=filetype)\n\n    if not p.exists() and not create:\n        return None\n\n    if not filetype:\n        if p.is_dir():\n            filetype = 'dir'\n        else:\n            filetype = p.ext or options.filetype or 'txt'\n\n    filetype = filetype.lower()\n\n    if not p.exists():\n        if not create:\n            return None\n        newfunc = getattr(vd, 'new_' + filetype, vd.getGlobals().get('new_' + filetype))\n        if not newfunc:\n            vd.warning('%s does not exist, creating new sheet' % p)\n            return vd.newSheet(p.name, 1, source=p)\n\n        vd.status('creating blank %s' % (p.given))\n        return newfunc(p)\n\n    openfunc = getattr(vd, 'open_' + filetype, vd.getGlobals().get('open_' + filetype))\n    if not openfunc:\n        vd.warning('unknown \"%s\" filetype' % filetype)\n        filetype = 'txt'\n        openfunc = vd.open_txt\n\n    vd.status('opening %s as %s' % (p.given, filetype))\n\n    return openfunc(p)\n\n\n@VisiData.api\ndef openSource(vd, p, filetype=None, create=False, **kwargs):\n    '''Return unloaded sheet object for *p* opened as the given *filetype* and with *kwargs* as option overrides. *p* can be a Path or a string (filename, url, or \"-\" for stdin).\n    when true, *create* will return a blank sheet, if file does not exist.'''\n    if not filetype:\n        filetype = options.getonly('filetype', 'global', '')\n\n    vs = None\n    if isinstance(p, str):\n        if '://' in p:\n            vs = vd.openPath(Path(p), filetype=filetype)  # convert to Path and recurse\n        elif p == '-':\n            vs = vd.openPath(vd.stdinSource, filetype=filetype)\n        else:\n            vs = vd.openPath(Path(p), filetype=filetype, create=create)  # convert to Path and recurse\n    else:\n        vs = vd.openPath(p, filetype=filetype, create=create)\n\n    for optname, optval in kwargs.items():\n        vs.options[optname] = optval\n\n    return vs\n\n\n#### enable external addons\n@VisiData.api\ndef open_txt(vd, p):\n    'Create sheet from `.txt` file at Path `p`, checking whether it is TSV.'\n    with p.open_text(encoding=vd.options.encoding) as fp:\n        try:\n            if options.delimiter in next(fp):    # peek at the first line\n                return vd.open_tsv(p)  # TSV often have .txt extension\n        except StopIteration:\n            return Sheet(p.name, columns=[SettableColumn()], source=p)\n        return TextSheet(p.name, source=p)\n\n\n@VisiData.api\ndef loadInternalSheet(vd, cls, p, **kwargs):\n    'Load internal sheet of given class.  Internal sheets are always tsv.'\n    vs = cls(p.name, source=p, **kwargs)\n    options._set('encoding', 'utf8', vs)\n    if p.exists():\n        vd.sheets.insert(0, vs)\n        vs.reload.__wrapped__(vs)\n        vd.sheets.pop(0)\n    return vs\n\n\nBaseSheet.addCommand('o', 'open-file', 'vd.push(openSource(inputFilename(\"open: \"), create=True))', 'Open file or URL')\nTableSheet.addCommand('zo', 'open-cell-file', 'vd.push(openSource(cursorDisplay))', 'Open file or URL from path in current cell')\n", "path": "visidata/_open.py"}], "after_files": [{"content": "from visidata import *\n\n\nvd.option('filetype', '', 'specify file type', replay=True)\n\n\n@VisiData.api\ndef inputFilename(vd, prompt, *args, **kwargs):\n    return vd.input(prompt, type=\"filename\", *args, completer=_completeFilename, **kwargs).strip()\n\n\n@VisiData.api\ndef inputPath(vd, *args, **kwargs):\n    return Path(vd.inputFilename(*args, **kwargs))\n\n\ndef _completeFilename(val, state):\n    i = val.rfind('/')\n    if i < 0:  # no /\n        base = ''\n        partial = val\n    elif i == 0: # root /\n        base = '/'\n        partial = val[1:]\n    else:\n        base = val[:i]\n        partial = val[i+1:]\n\n    files = []\n    for f in os.listdir(Path(base or '.')):\n        if f.startswith(partial):\n            files.append(os.path.join(base, f))\n\n    files.sort()\n    return files[state%len(files)]\n\n\n@VisiData.api\ndef openPath(vd, p, filetype=None, create=False):\n    '''Call ``open_<filetype>(p)`` or ``openurl_<p.scheme>(p, filetype)``.  Return constructed but unloaded sheet of appropriate type.\n    If True, *create* will return a new, blank **Sheet** if file does not exist.'''\n    if p.scheme and not p.has_fp():\n        schemes = p.scheme.split('+')\n        openfuncname = 'openurl_' + schemes[-1]\n\n        openfunc = getattr(vd, openfuncname, None) or vd.getGlobals().get(openfuncname, None)\n        if not openfunc:\n            vd.fail(f'no loader for url scheme: {p.scheme}')\n\n        return openfunc(p, filetype=filetype)\n\n    if not p.exists() and not create:\n        return None\n\n    if not filetype:\n        if p.is_dir():\n            filetype = 'dir'\n        else:\n            filetype = p.ext or options.filetype or 'txt'\n\n    filetype = filetype.lower()\n\n    if not p.exists():\n        if not create:\n            return None\n        newfunc = getattr(vd, 'new_' + filetype, vd.getGlobals().get('new_' + filetype))\n        if not newfunc:\n            vd.warning('%s does not exist, creating new sheet' % p)\n            return vd.newSheet(p.name, 1, source=p)\n\n        vd.status('creating blank %s' % (p.given))\n        return newfunc(p)\n\n    openfunc = getattr(vd, 'open_' + filetype, vd.getGlobals().get('open_' + filetype))\n    if not openfunc:\n        vd.warning('unknown \"%s\" filetype' % filetype)\n        filetype = 'txt'\n        openfunc = vd.open_txt\n\n    vd.status('opening %s as %s' % (p.given, filetype))\n\n    return openfunc(p)\n\n\n@VisiData.api\ndef openSource(vd, p, filetype=None, create=False, **kwargs):\n    '''Return unloaded sheet object for *p* opened as the given *filetype* and with *kwargs* as option overrides. *p* can be a Path or a string (filename, url, or \"-\" for stdin).\n    when true, *create* will return a blank sheet, if file does not exist.'''\n    if not filetype:\n        filetype = options.getonly('filetype', 'global', '')\n\n    vs = None\n    if isinstance(p, str):\n        if '://' in p:\n            vs = vd.openPath(Path(p), filetype=filetype)  # convert to Path and recurse\n        elif p == '-':\n            vs = vd.openPath(vd.stdinSource, filetype=filetype)\n        else:\n            vs = vd.openPath(Path(p), filetype=filetype, create=create)  # convert to Path and recurse\n    else:\n        vs = vd.openPath(p, filetype=filetype, create=create)\n\n    for optname, optval in kwargs.items():\n        vs.options[optname] = optval\n\n    return vs\n\n\n#### enable external addons\n@VisiData.api\ndef open_txt(vd, p):\n    'Create sheet from `.txt` file at Path `p`, checking whether it is TSV.'\n    with p.open_text(encoding=vd.options.encoding) as fp:\n        try:\n            if options.delimiter in next(fp):    # peek at the first line\n                return vd.open_tsv(p)  # TSV often have .txt extension\n        except StopIteration:\n            return Sheet(p.name, columns=[SettableColumn()], source=p)\n        return TextSheet(p.name, source=p)\n\n\n@VisiData.api\ndef loadInternalSheet(vd, cls, p, **kwargs):\n    'Load internal sheet of given class.  Internal sheets are always tsv.'\n    vs = cls(p.name, source=p, **kwargs)\n    options._set('encoding', 'utf8', vs)\n    if p.exists():\n        vd.sheets.insert(0, vs)\n        vs.reload.__wrapped__(vs)\n        vd.sheets.pop(0)\n    return vs\n\n\nBaseSheet.addCommand('o', 'open-file', 'vd.push(openSource(inputFilename(\"open: \"), create=True))', 'Open file or URL')\nTableSheet.addCommand('zo', 'open-cell-file', 'vd.push(openSource(cursorDisplay) or fail(f\"file {cursorDisplay} does not exist\"))', 'Open file or URL from path in current cell')\n", "path": "visidata/_open.py"}]}