I have a function that renders an input file to a custom format. I want that a user can start this script in one terminal to view the rendered output with a pager. When he edits the source-file in another terminal and saves, these changed should be rerendered and updated in the pager.
Detecting these changes and rerendering them works. The problem is the updating of the pager.
After some search I found that less can do this reloading when pressing 'R':
R Repaint screen, discarding buffered input.
So I tried to implement this behavior in my code:
pager_process = subprocess.Popen(['less', filepath], stdin=subprocess.PIPE)
...
pager_process.stdin.write(b'R') # HERE: this should reload less but doesn't
But this didn't work.
Any idea or deeper knowledge that I don't know of?
Original Codesource = Path(source) # some sort of input file
def render_source() -> str:
try:
return convert(fp=source) # renders the input-file in a wished format
except SyntaxError as error:
return '\n'.join(traceback.format_exception(type(error), error, error.__traceback__)) # in case rendering fails
def update_tmpfile(new: str) -> None:
tmp.truncate(0)
tmp.seek(0)
tmp.write(new)
tmp.flush()
with tempfile.NamedTemporaryFile('w+') as tmp:
last_mtime = source.stat().st_mtime_ns
content = render_source()
update_tmpfile(content)
pager_process = subprocess.Popen(['less', tmp.name], stdin=subprocess.PIPE)
try:
while pager_process.poll() is None: # not exited
time.sleep(0.1)
current_mtime = source.stat().st_mtime_ns
if last_mtime != current_mtime: # source changed -> rerender
last_mtime = current_mtime
content = render_source()
update_tmpfile(content)
pager_process.stdin.write(b'R') # HERE: this should reload less but doesn't
except Exception:
pager_process.kill()
raise
After some research I finally managed to find a solution.
Instead of an external pager process I use the pypager library
I create a pager instance with
pager = pypager.Pager()
pager.add_source(pypager.StringSource("")) # 0 index buffer
pager.add_source(pypager.StringSource("")) # page-buffer that gets replaced
and can update the rendered content with
content = render_source()
pager.remove_current_source()
pager.add_source(pypager.StringSource(content))
pager.application.invalidate()