prompt: We are currently solving the following issue within our repository. Here is the issue text:
  --- BEGIN ISSUE ---
  REPL history is lost on (quit)
  REPL history is not flushed to disk if the REPL is exited using `(quit)`. 
  
  A workaround is to remember to use `CTRL-D` to exit the REPL.
  
  Would be nice if `(quit)` also worked.
  
  --- END ISSUE ---
  
  Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
  --- BEGIN FILES ---
  Path: `hy/completer.py`
  Content:
  ```
  1 # Copyright 2017 the authors.
  2 # This file is part of Hy, which is free software licensed under the Expat
  3 # license. See the LICENSE.
  4 
  5 import contextlib
  6 import os
  7 import re
  8 import sys
  9 
  10 import hy.macros
  11 import hy.compiler
  12 from hy._compat import builtins, string_types
  13 
  14 
  15 docomplete = True
  16 
  17 try:
  18     import readline
  19 except ImportError:
  20     try:
  21         import pyreadline.rlmain
  22         import pyreadline.unicode_helper  # NOQA
  23         import readline
  24     except ImportError:
  25         docomplete = False
  26 
  27 if sys.platform == 'darwin' and 'libedit' in readline.__doc__:
  28     readline_bind = "bind ^I rl_complete"
  29 else:
  30     readline_bind = "tab: complete"
  31 
  32 
  33 class Completer(object):
  34 
  35     def __init__(self, namespace={}):
  36         if not isinstance(namespace, dict):
  37             raise TypeError('namespace must be a dictionary')
  38         self.namespace = namespace
  39         self.path = [hy.compiler._compile_table,
  40                      builtins.__dict__,
  41                      hy.macros._hy_macros[None],
  42                      namespace]
  43         self.tag_path = [hy.macros._hy_tag[None]]
  44         if '__name__' in namespace:
  45             module_name = namespace['__name__']
  46             self.path.append(hy.macros._hy_macros[module_name])
  47             self.tag_path.append(hy.macros._hy_tag[module_name])
  48 
  49     def attr_matches(self, text):
  50         # Borrowed from IPython's completer
  51         m = re.match(r"(\S+(\.[\w-]+)*)\.([\w-]*)$", text)
  52 
  53         if m:
  54             expr, attr = m.group(1, 3)
  55             attr = attr.replace("-", "_")
  56             expr = expr.replace("-", "_")
  57         else:
  58             return []
  59 
  60         try:
  61             obj = eval(expr, self.namespace)
  62             words = dir(obj)
  63         except Exception:
  64             return []
  65 
  66         n = len(attr)
  67         matches = []
  68         for w in words:
  69             if w[:n] == attr:
  70                 matches.append("{}.{}".format(
  71                     expr.replace("_", "-"), w.replace("_", "-")))
  72         return matches
  73 
  74     def global_matches(self, text):
  75         matches = []
  76         for p in self.path:
  77             for k in p.keys():
  78                 if isinstance(k, string_types):
  79                     k = k.replace("_", "-")
  80                     if k.startswith(text):
  81                         matches.append(k)
  82         return matches
  83 
  84     def tag_matches(self, text):
  85         text = text[1:]
  86         matches = []
  87         for p in self.tag_path:
  88             for k in p.keys():
  89                 if isinstance(k, string_types):
  90                     if k.startswith(text):
  91                         matches.append("#{}".format(k))
  92         return matches
  93 
  94     def complete(self, text, state):
  95         if text.startswith("#"):
  96             matches = self.tag_matches(text)
  97         elif "." in text:
  98             matches = self.attr_matches(text)
  99         else:
  100             matches = self.global_matches(text)
  101         try:
  102             return matches[state]
  103         except IndexError:
  104             return None
  105 
  106 
  107 @contextlib.contextmanager
  108 def completion(completer=None):
  109     delims = "()[]{} "
  110     if not completer:
  111         completer = Completer()
  112 
  113     if docomplete:
  114         readline.set_completer(completer.complete)
  115         readline.set_completer_delims(delims)
  116 
  117         history = os.path.expanduser("~/.hy-history")
  118         readline.parse_and_bind("set blink-matching-paren on")
  119 
  120         try:
  121             readline.read_history_file(history)
  122         except IOError:
  123             open(history, 'a').close()
  124 
  125         readline.parse_and_bind(readline_bind)
  126 
  127     yield
  128 
  129     if docomplete:
  130         readline.write_history_file(history)
  131
  ```
  --- 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/hy/completer.py b/hy/completer.py
  --- a/hy/completer.py
  +++ b/hy/completer.py
  @@ -124,7 +124,8 @@
   
           readline.parse_and_bind(readline_bind)
   
  -    yield
  -
  -    if docomplete:
  -        readline.write_history_file(history)
  +    try:
  +        yield
  +    finally:
  +        if docomplete:
  +            readline.write_history_file(history)
  
verification_info: {"golden_diff": "diff --git a/hy/completer.py b/hy/completer.py\n--- a/hy/completer.py\n+++ b/hy/completer.py\n@@ -124,7 +124,8 @@\n \n         readline.parse_and_bind(readline_bind)\n \n-    yield\n-\n-    if docomplete:\n-        readline.write_history_file(history)\n+    try:\n+        yield\n+    finally:\n+        if docomplete:\n+            readline.write_history_file(history)\n", "issue": "REPL history is lost on (quit)\nREPL history is not flushed to disk if the REPL is exited using `(quit)`. \r\n\r\nA workaround is to remember to use `CTRL-D` to exit the REPL.\r\n\r\nWould be nice if `(quit)` also worked.\n", "before_files": [{"content": "# Copyright 2017 the authors.\n# This file is part of Hy, which is free software licensed under the Expat\n# license. See the LICENSE.\n\nimport contextlib\nimport os\nimport re\nimport sys\n\nimport hy.macros\nimport hy.compiler\nfrom hy._compat import builtins, string_types\n\n\ndocomplete = True\n\ntry:\n    import readline\nexcept ImportError:\n    try:\n        import pyreadline.rlmain\n        import pyreadline.unicode_helper  # NOQA\n        import readline\n    except ImportError:\n        docomplete = False\n\nif sys.platform == 'darwin' and 'libedit' in readline.__doc__:\n    readline_bind = \"bind ^I rl_complete\"\nelse:\n    readline_bind = \"tab: complete\"\n\n\nclass Completer(object):\n\n    def __init__(self, namespace={}):\n        if not isinstance(namespace, dict):\n            raise TypeError('namespace must be a dictionary')\n        self.namespace = namespace\n        self.path = [hy.compiler._compile_table,\n                     builtins.__dict__,\n                     hy.macros._hy_macros[None],\n                     namespace]\n        self.tag_path = [hy.macros._hy_tag[None]]\n        if '__name__' in namespace:\n            module_name = namespace['__name__']\n            self.path.append(hy.macros._hy_macros[module_name])\n            self.tag_path.append(hy.macros._hy_tag[module_name])\n\n    def attr_matches(self, text):\n        # Borrowed from IPython's completer\n        m = re.match(r\"(\\S+(\\.[\\w-]+)*)\\.([\\w-]*)$\", text)\n\n        if m:\n            expr, attr = m.group(1, 3)\n            attr = attr.replace(\"-\", \"_\")\n            expr = expr.replace(\"-\", \"_\")\n        else:\n            return []\n\n        try:\n            obj = eval(expr, self.namespace)\n            words = dir(obj)\n        except Exception:\n            return []\n\n        n = len(attr)\n        matches = []\n        for w in words:\n            if w[:n] == attr:\n                matches.append(\"{}.{}\".format(\n                    expr.replace(\"_\", \"-\"), w.replace(\"_\", \"-\")))\n        return matches\n\n    def global_matches(self, text):\n        matches = []\n        for p in self.path:\n            for k in p.keys():\n                if isinstance(k, string_types):\n                    k = k.replace(\"_\", \"-\")\n                    if k.startswith(text):\n                        matches.append(k)\n        return matches\n\n    def tag_matches(self, text):\n        text = text[1:]\n        matches = []\n        for p in self.tag_path:\n            for k in p.keys():\n                if isinstance(k, string_types):\n                    if k.startswith(text):\n                        matches.append(\"#{}\".format(k))\n        return matches\n\n    def complete(self, text, state):\n        if text.startswith(\"#\"):\n            matches = self.tag_matches(text)\n        elif \".\" in text:\n            matches = self.attr_matches(text)\n        else:\n            matches = self.global_matches(text)\n        try:\n            return matches[state]\n        except IndexError:\n            return None\n\n\n@contextlib.contextmanager\ndef completion(completer=None):\n    delims = \"()[]{} \"\n    if not completer:\n        completer = Completer()\n\n    if docomplete:\n        readline.set_completer(completer.complete)\n        readline.set_completer_delims(delims)\n\n        history = os.path.expanduser(\"~/.hy-history\")\n        readline.parse_and_bind(\"set blink-matching-paren on\")\n\n        try:\n            readline.read_history_file(history)\n        except IOError:\n            open(history, 'a').close()\n\n        readline.parse_and_bind(readline_bind)\n\n    yield\n\n    if docomplete:\n        readline.write_history_file(history)\n", "path": "hy/completer.py"}], "after_files": [{"content": "# Copyright 2017 the authors.\n# This file is part of Hy, which is free software licensed under the Expat\n# license. See the LICENSE.\n\nimport contextlib\nimport os\nimport re\nimport sys\n\nimport hy.macros\nimport hy.compiler\nfrom hy._compat import builtins, string_types\n\n\ndocomplete = True\n\ntry:\n    import readline\nexcept ImportError:\n    try:\n        import pyreadline.rlmain\n        import pyreadline.unicode_helper  # NOQA\n        import readline\n    except ImportError:\n        docomplete = False\n\nif sys.platform == 'darwin' and 'libedit' in readline.__doc__:\n    readline_bind = \"bind ^I rl_complete\"\nelse:\n    readline_bind = \"tab: complete\"\n\n\nclass Completer(object):\n\n    def __init__(self, namespace={}):\n        if not isinstance(namespace, dict):\n            raise TypeError('namespace must be a dictionary')\n        self.namespace = namespace\n        self.path = [hy.compiler._compile_table,\n                     builtins.__dict__,\n                     hy.macros._hy_macros[None],\n                     namespace]\n        self.tag_path = [hy.macros._hy_tag[None]]\n        if '__name__' in namespace:\n            module_name = namespace['__name__']\n            self.path.append(hy.macros._hy_macros[module_name])\n            self.tag_path.append(hy.macros._hy_tag[module_name])\n\n    def attr_matches(self, text):\n        # Borrowed from IPython's completer\n        m = re.match(r\"(\\S+(\\.[\\w-]+)*)\\.([\\w-]*)$\", text)\n\n        if m:\n            expr, attr = m.group(1, 3)\n            attr = attr.replace(\"-\", \"_\")\n            expr = expr.replace(\"-\", \"_\")\n        else:\n            return []\n\n        try:\n            obj = eval(expr, self.namespace)\n            words = dir(obj)\n        except Exception:\n            return []\n\n        n = len(attr)\n        matches = []\n        for w in words:\n            if w[:n] == attr:\n                matches.append(\"{}.{}\".format(\n                    expr.replace(\"_\", \"-\"), w.replace(\"_\", \"-\")))\n        return matches\n\n    def global_matches(self, text):\n        matches = []\n        for p in self.path:\n            for k in p.keys():\n                if isinstance(k, string_types):\n                    k = k.replace(\"_\", \"-\")\n                    if k.startswith(text):\n                        matches.append(k)\n        return matches\n\n    def tag_matches(self, text):\n        text = text[1:]\n        matches = []\n        for p in self.tag_path:\n            for k in p.keys():\n                if isinstance(k, string_types):\n                    if k.startswith(text):\n                        matches.append(\"#{}\".format(k))\n        return matches\n\n    def complete(self, text, state):\n        if text.startswith(\"#\"):\n            matches = self.tag_matches(text)\n        elif \".\" in text:\n            matches = self.attr_matches(text)\n        else:\n            matches = self.global_matches(text)\n        try:\n            return matches[state]\n        except IndexError:\n            return None\n\n\n@contextlib.contextmanager\ndef completion(completer=None):\n    delims = \"()[]{} \"\n    if not completer:\n        completer = Completer()\n\n    if docomplete:\n        readline.set_completer(completer.complete)\n        readline.set_completer_delims(delims)\n\n        history = os.path.expanduser(\"~/.hy-history\")\n        readline.parse_and_bind(\"set blink-matching-paren on\")\n\n        try:\n            readline.read_history_file(history)\n        except IOError:\n            open(history, 'a').close()\n\n        readline.parse_and_bind(readline_bind)\n\n    try:\n        yield\n    finally:\n        if docomplete:\n            readline.write_history_file(history)\n", "path": "hy/completer.py"}]}