Coverage for vibefpmgui/formatter.py: 73%

27 statements  

« prev     ^ index     » next       coverage.py v7.16.2, created at 2026-11-01 20:51 +0000

1"""Formatting Fortran files in the editor with fprettify. 

2 

3`fprettify <https://github.com/fortran-lang/fprettify>`_ reads the editor's 

4text on stdin and writes the formatted text to stdout, so unsaved changes are 

5formatted too and the result is one undoable edit. It runs in the folder of 

6the file, so a ``.fprettify.rc`` there (or in a parent folder, or ``~``) 

7applies. Like fortitude, it only understands free-form Fortran. 

8""" 

9 

10from __future__ import annotations 

11 

12import os 

13import shutil 

14import subprocess 

15from pathlib import Path 

16 

17from .console import NO_WINDOW 

18from .lint import LINT_EXTS 

19 

20FORMAT_EXTS = LINT_EXTS 

21 

22 

23def executable() -> str | None: 

24 return shutil.which("fprettify") 

25 

26 

27def can_format(path: Path) -> bool: 

28 return path.suffix.lower() in FORMAT_EXTS 

29 

30 

31def format_text(text: str, path: Path, timeout: float = 60) -> tuple[str | None, str]: 

32 """(formatted text, "") or (None, why it failed).""" 

33 program = executable() 

34 if program is None: 34 ↛ 35line 34 didn't jump to line 35 because the condition on line 34 was never true

35 return None, "fprettify was not found on the PATH." 

36 # fprettify's own regexes trigger SyntaxWarnings on newer Pythons. 

37 env = dict(os.environ, PYTHONWARNINGS="ignore") 

38 try: 

39 out = subprocess.run([program, "-"], input=text, capture_output=True, text=True, 

40 encoding="utf-8", errors="replace", cwd=path.parent, 

41 timeout=timeout, env=env, check=False, **NO_WINDOW) 

42 except (OSError, subprocess.SubprocessError) as exc: 

43 return None, str(exc) 

44 if out.returncode != 0: 44 ↛ 45line 44 didn't jump to line 45 because the condition on line 44 was never true

45 lines = [line for line in out.stderr.splitlines() if line.strip()] 

46 return None, lines[-1] if lines else f"fprettify exited with code {out.returncode}" 

47 if text.strip() and not out.stdout.strip(): 47 ↛ 48line 47 didn't jump to line 48 because the condition on line 47 was never true

48 return None, "fprettify returned no text." 

49 return out.stdout, ""