| 654 | |
| 655 | |
| 656 | class Editor: |
| 657 | def __init__( |
| 658 | self, |
| 659 | editor: str | None = None, |
| 660 | env: cabc.Mapping[str, str] | None = None, |
| 661 | require_save: bool = True, |
| 662 | extension: str = ".txt", |
| 663 | ) -> None: |
| 664 | self.editor = editor |
| 665 | self.env = env |
| 666 | self.require_save = require_save |
| 667 | self.extension = extension |
| 668 | |
| 669 | def get_editor(self) -> str: |
| 670 | if self.editor is not None: |
| 671 | return self.editor |
| 672 | for key in "VISUAL", "EDITOR": |
| 673 | rv = os.environ.get(key) |
| 674 | if rv: |
| 675 | return rv |
| 676 | if WIN: |
| 677 | return "notepad" |
| 678 | |
| 679 | from shutil import which |
| 680 | |
| 681 | for editor in "sensible-editor", "vim", "nano": |
| 682 | if which(editor) is not None: |
| 683 | return editor |
| 684 | return "vi" |
| 685 | |
| 686 | def edit_files(self, filenames: cabc.Iterable[str]) -> None: |
| 687 | """Open files in the user's editor.""" |
| 688 | import shlex |
| 689 | import subprocess |
| 690 | |
| 691 | editor = self.get_editor() |
| 692 | environ: dict[str, str] | None = None |
| 693 | |
| 694 | if self.env: |
| 695 | environ = os.environ.copy() |
| 696 | environ.update(self.env) |
| 697 | |
| 698 | try: |
| 699 | # Split in POSIX mode (the default) for the same reasons as |
| 700 | # in pager(): strips quotes from tokens and preserves quoted |
| 701 | # Windows paths. |
| 702 | c = subprocess.Popen( |
| 703 | args=shlex.split(editor) + list(filenames), |
| 704 | env=environ, |
| 705 | ) |
| 706 | exit_code = c.wait() |
| 707 | if exit_code != 0: |
| 708 | raise ClickException( |
| 709 | _("{editor}: Editing failed").format(editor=editor) |
| 710 | ) |
| 711 | except OSError as e: |
| 712 | raise ClickException( |
| 713 | _("{editor}: Editing failed: {e}").format(editor=editor, e=e) |
no outgoing calls
searching dependent graphs…