prompt: We are currently solving the following issue within our repository. Here is the issue text:
  --- BEGIN ISSUE ---
  fixed width saver truncates data if columns are not fully expanded
  **Small description**
  
  If you save or syscopy a table as `fixed` format, and the visible column width is less than the width of the data in the column, the data is truncated. Also, the resulting file is not a valid fixed width format file as the columns are not aligned with the headers.
  
  **Expected result**
  
  Saving or copying a table when the columns are not fully expanded should yield the same result as when the columns are expanded.
  
  **Actual result with screenshot**
  ![image](https://user-images.githubusercontent.com/2499066/231616002-553a1a46-0b56-4950-b3eb-90507a77b823.png)
  
  **Steps to reproduce with sample data and a .vd**
  [test-vd-fixed.zip](https://github.com/saulpw/visidata/files/11217144/test-vd-fixed.zip)
  
  **Additional context**
  saul.pw/VisiData v2.11
  
  
  --- 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/loaders/fixed_width.py`
  Content:
  ```
  1 
  2 from visidata import VisiData, vd, Sheet, Column, Progress, SequenceSheet
  3 
  4 
  5 vd.option('fixed_rows', 1000, 'number of rows to check for fixed width columns')
  6 vd.option('fixed_maxcols', 0, 'max number of fixed-width columns to create (0 is no max)')
  7 
  8 @VisiData.api
  9 def open_fixed(vd, p):
  10     return FixedWidthColumnsSheet(p.name, source=p, headerlines=[])
  11 
  12 class FixedWidthColumn(Column):
  13     def __init__(self, name, i, j, **kwargs):
  14         super().__init__(name, **kwargs)
  15         self.i, self.j = i, j
  16 
  17     def calcValue(self, row):
  18         return row[0][self.i:self.j]
  19 
  20     def putValue(self, row, value):
  21         value = str(value)[:self.j-self.i]
  22         j = self.j or len(row)
  23         row[0] = row[0][:self.i] + '%-*s' % (j-self.i, value) + row[0][self.j:]
  24 
  25 def columnize(rows):
  26     'Generate (i,j) indexes for fixed-width columns found in rows'
  27 
  28     ## find all character columns that are not spaces ever
  29     allNonspaces = set()
  30     for r in rows:
  31         for i, ch in enumerate(r):
  32             if not ch.isspace():
  33                 allNonspaces.add(i)
  34 
  35     colstart = 0
  36     prev = 0
  37 
  38     # collapse fields
  39     for i in allNonspaces:
  40         if i > prev+1:
  41             yield colstart, i
  42             colstart = i
  43         prev = i
  44 
  45     yield colstart, prev+1   # final column gets rest of line
  46 
  47 
  48 class FixedWidthColumnsSheet(SequenceSheet):
  49     rowtype = 'lines'  # rowdef: [line] (wrapping in list makes it unique and modifiable)
  50     def addRow(self, row, index=None):
  51         Sheet.addRow(self, row, index=index)
  52 
  53     def iterload(self):
  54         itsource = iter(self.source)
  55 
  56         # compute fixed width columns from first fixed_rows lines
  57         maxcols = self.options.fixed_maxcols
  58         self.columns = []
  59         fixedRows = list([x] for x in self.optlines(itsource, 'fixed_rows'))
  60         for i, j in columnize(list(r[0] for r in fixedRows)):
  61             if maxcols and self.nCols >= maxcols-1:
  62                 self.addColumn(FixedWidthColumn('', i, None))
  63                 break
  64             else:
  65                 self.addColumn(FixedWidthColumn('', i, j))
  66 
  67         yield from fixedRows
  68 
  69         self.setColNames(self.headerlines)
  70 
  71         yield from ([line] for line in itsource)
  72 
  73     def setCols(self, headerlines):
  74         self.headerlines = headerlines
  75 
  76 
  77 @VisiData.api
  78 def save_fixed(vd, p, *vsheets):
  79     with p.open(mode='w', encoding=vsheets[0].options.save_encoding) as fp:
  80         for sheet in vsheets:
  81             if len(vsheets) > 1:
  82                 fp.write('%s\n\n' % sheet.name)
  83 
  84             widths = {}  # Column -> width:int
  85             # headers
  86             for col in Progress(sheet.visibleCols, gerund='sizing'):
  87                 maxWidth = col.getMaxWidth(sheet.rows)
  88                 widths[col] = col.width if col.width >= maxWidth else sheet.options.default_width or maxWidth
  89                 fp.write(('{0:%s} ' % widths[col]).format(col.name))
  90             fp.write('\n')
  91 
  92             # rows
  93             with Progress(gerund='saving'):
  94                 for dispvals in sheet.iterdispvals(format=True):
  95                     for col, val in dispvals.items():
  96                         fp.write(('{0:%s%s.%s} ' % ('>' if vd.isNumeric(col) else '<', widths[col], widths[col])).format(val))
  97                     fp.write('\n')
  98 
  99             vd.status('%s save finished' % p)
  100
  ```
  --- 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/loaders/fixed_width.py b/visidata/loaders/fixed_width.py
  --- a/visidata/loaders/fixed_width.py
  +++ b/visidata/loaders/fixed_width.py
  @@ -84,8 +84,7 @@
               widths = {}  # Column -> width:int
               # headers
               for col in Progress(sheet.visibleCols, gerund='sizing'):
  -                maxWidth = col.getMaxWidth(sheet.rows)
  -                widths[col] = col.width if col.width >= maxWidth else sheet.options.default_width or maxWidth
  +                widths[col] = col.getMaxWidth(sheet.rows)  #1849 
                   fp.write(('{0:%s} ' % widths[col]).format(col.name))
               fp.write('\n')
  
verification_info: {"golden_diff": "diff --git a/visidata/loaders/fixed_width.py b/visidata/loaders/fixed_width.py\n--- a/visidata/loaders/fixed_width.py\n+++ b/visidata/loaders/fixed_width.py\n@@ -84,8 +84,7 @@\n             widths = {}  # Column -> width:int\n             # headers\n             for col in Progress(sheet.visibleCols, gerund='sizing'):\n-                maxWidth = col.getMaxWidth(sheet.rows)\n-                widths[col] = col.width if col.width >= maxWidth else sheet.options.default_width or maxWidth\n+                widths[col] = col.getMaxWidth(sheet.rows)  #1849 \n                 fp.write(('{0:%s} ' % widths[col]).format(col.name))\n             fp.write('\\n')\n", "issue": "fixed width saver truncates data if columns are not fully expanded\n**Small description**\r\n\r\nIf you save or syscopy a table as `fixed` format, and the visible column width is less than the width of the data in the column, the data is truncated. Also, the resulting file is not a valid fixed width format file as the columns are not aligned with the headers.\r\n\r\n**Expected result**\r\n\r\nSaving or copying a table when the columns are not fully expanded should yield the same result as when the columns are expanded.\r\n\r\n**Actual result with screenshot**\r\n![image](https://user-images.githubusercontent.com/2499066/231616002-553a1a46-0b56-4950-b3eb-90507a77b823.png)\r\n\r\n**Steps to reproduce with sample data and a .vd**\r\n[test-vd-fixed.zip](https://github.com/saulpw/visidata/files/11217144/test-vd-fixed.zip)\r\n\r\n**Additional context**\r\nsaul.pw/VisiData v2.11\r\n\n", "before_files": [{"content": "\nfrom visidata import VisiData, vd, Sheet, Column, Progress, SequenceSheet\n\n\nvd.option('fixed_rows', 1000, 'number of rows to check for fixed width columns')\nvd.option('fixed_maxcols', 0, 'max number of fixed-width columns to create (0 is no max)')\n\n@VisiData.api\ndef open_fixed(vd, p):\n    return FixedWidthColumnsSheet(p.name, source=p, headerlines=[])\n\nclass FixedWidthColumn(Column):\n    def __init__(self, name, i, j, **kwargs):\n        super().__init__(name, **kwargs)\n        self.i, self.j = i, j\n\n    def calcValue(self, row):\n        return row[0][self.i:self.j]\n\n    def putValue(self, row, value):\n        value = str(value)[:self.j-self.i]\n        j = self.j or len(row)\n        row[0] = row[0][:self.i] + '%-*s' % (j-self.i, value) + row[0][self.j:]\n\ndef columnize(rows):\n    'Generate (i,j) indexes for fixed-width columns found in rows'\n\n    ## find all character columns that are not spaces ever\n    allNonspaces = set()\n    for r in rows:\n        for i, ch in enumerate(r):\n            if not ch.isspace():\n                allNonspaces.add(i)\n\n    colstart = 0\n    prev = 0\n\n    # collapse fields\n    for i in allNonspaces:\n        if i > prev+1:\n            yield colstart, i\n            colstart = i\n        prev = i\n\n    yield colstart, prev+1   # final column gets rest of line\n\n\nclass FixedWidthColumnsSheet(SequenceSheet):\n    rowtype = 'lines'  # rowdef: [line] (wrapping in list makes it unique and modifiable)\n    def addRow(self, row, index=None):\n        Sheet.addRow(self, row, index=index)\n\n    def iterload(self):\n        itsource = iter(self.source)\n\n        # compute fixed width columns from first fixed_rows lines\n        maxcols = self.options.fixed_maxcols\n        self.columns = []\n        fixedRows = list([x] for x in self.optlines(itsource, 'fixed_rows'))\n        for i, j in columnize(list(r[0] for r in fixedRows)):\n            if maxcols and self.nCols >= maxcols-1:\n                self.addColumn(FixedWidthColumn('', i, None))\n                break\n            else:\n                self.addColumn(FixedWidthColumn('', i, j))\n\n        yield from fixedRows\n\n        self.setColNames(self.headerlines)\n\n        yield from ([line] for line in itsource)\n\n    def setCols(self, headerlines):\n        self.headerlines = headerlines\n\n\n@VisiData.api\ndef save_fixed(vd, p, *vsheets):\n    with p.open(mode='w', encoding=vsheets[0].options.save_encoding) as fp:\n        for sheet in vsheets:\n            if len(vsheets) > 1:\n                fp.write('%s\\n\\n' % sheet.name)\n\n            widths = {}  # Column -> width:int\n            # headers\n            for col in Progress(sheet.visibleCols, gerund='sizing'):\n                maxWidth = col.getMaxWidth(sheet.rows)\n                widths[col] = col.width if col.width >= maxWidth else sheet.options.default_width or maxWidth\n                fp.write(('{0:%s} ' % widths[col]).format(col.name))\n            fp.write('\\n')\n\n            # rows\n            with Progress(gerund='saving'):\n                for dispvals in sheet.iterdispvals(format=True):\n                    for col, val in dispvals.items():\n                        fp.write(('{0:%s%s.%s} ' % ('>' if vd.isNumeric(col) else '<', widths[col], widths[col])).format(val))\n                    fp.write('\\n')\n\n            vd.status('%s save finished' % p)\n", "path": "visidata/loaders/fixed_width.py"}], "after_files": [{"content": "\nfrom visidata import VisiData, vd, Sheet, Column, Progress, SequenceSheet\n\n\nvd.option('fixed_rows', 1000, 'number of rows to check for fixed width columns')\nvd.option('fixed_maxcols', 0, 'max number of fixed-width columns to create (0 is no max)')\n\n@VisiData.api\ndef open_fixed(vd, p):\n    return FixedWidthColumnsSheet(p.name, source=p, headerlines=[])\n\nclass FixedWidthColumn(Column):\n    def __init__(self, name, i, j, **kwargs):\n        super().__init__(name, **kwargs)\n        self.i, self.j = i, j\n\n    def calcValue(self, row):\n        return row[0][self.i:self.j]\n\n    def putValue(self, row, value):\n        value = str(value)[:self.j-self.i]\n        j = self.j or len(row)\n        row[0] = row[0][:self.i] + '%-*s' % (j-self.i, value) + row[0][self.j:]\n\ndef columnize(rows):\n    'Generate (i,j) indexes for fixed-width columns found in rows'\n\n    ## find all character columns that are not spaces ever\n    allNonspaces = set()\n    for r in rows:\n        for i, ch in enumerate(r):\n            if not ch.isspace():\n                allNonspaces.add(i)\n\n    colstart = 0\n    prev = 0\n\n    # collapse fields\n    for i in allNonspaces:\n        if i > prev+1:\n            yield colstart, i\n            colstart = i\n        prev = i\n\n    yield colstart, prev+1   # final column gets rest of line\n\n\nclass FixedWidthColumnsSheet(SequenceSheet):\n    rowtype = 'lines'  # rowdef: [line] (wrapping in list makes it unique and modifiable)\n    def addRow(self, row, index=None):\n        Sheet.addRow(self, row, index=index)\n\n    def iterload(self):\n        itsource = iter(self.source)\n\n        # compute fixed width columns from first fixed_rows lines\n        maxcols = self.options.fixed_maxcols\n        self.columns = []\n        fixedRows = list([x] for x in self.optlines(itsource, 'fixed_rows'))\n        for i, j in columnize(list(r[0] for r in fixedRows)):\n            if maxcols and self.nCols >= maxcols-1:\n                self.addColumn(FixedWidthColumn('', i, None))\n                break\n            else:\n                self.addColumn(FixedWidthColumn('', i, j))\n\n        yield from fixedRows\n\n        self.setColNames(self.headerlines)\n\n        yield from ([line] for line in itsource)\n\n    def setCols(self, headerlines):\n        self.headerlines = headerlines\n\n\n@VisiData.api\ndef save_fixed(vd, p, *vsheets):\n    with p.open(mode='w', encoding=vsheets[0].options.save_encoding) as fp:\n        for sheet in vsheets:\n            if len(vsheets) > 1:\n                fp.write('%s\\n\\n' % sheet.name)\n\n            widths = {}  # Column -> width:int\n            # headers\n            for col in Progress(sheet.visibleCols, gerund='sizing'):\n                widths[col] = col.getMaxWidth(sheet.rows)  #1849 \n                fp.write(('{0:%s} ' % widths[col]).format(col.name))\n            fp.write('\\n')\n\n            # rows\n            with Progress(gerund='saving'):\n                for dispvals in sheet.iterdispvals(format=True):\n                    for col, val in dispvals.items():\n                        fp.write(('{0:%s%s.%s} ' % ('>' if vd.isNumeric(col) else '<', widths[col], widths[col])).format(val))\n                    fp.write('\\n')\n\n            vd.status('%s save finished' % p)\n", "path": "visidata/loaders/fixed_width.py"}]}