Coverage for sources/mimeogram/edit.py: 42%

32 statements  

« prev     ^ index     » next       coverage.py v7.6.12, created at 2025-02-16 01:42 +0000

1# vim: set filetype=python fileencoding=utf-8: 

2# -*- coding: utf-8 -*- 

3 

4#============================================================================# 

5# # 

6# Licensed under the Apache License, Version 2.0 (the "License"); # 

7# you may not use this file except in compliance with the License. # 

8# You may obtain a copy of the License at # 

9# # 

10# http://www.apache.org/licenses/LICENSE-2.0 # 

11# # 

12# Unless required by applicable law or agreed to in writing, software # 

13# distributed under the License is distributed on an "AS IS" BASIS, # 

14# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # 

15# See the License for the specific language governing permissions and # 

16# limitations under the License. # 

17# # 

18#============================================================================# 

19 

20 

21''' System editor interaction. ''' 

22 

23 

24from __future__ import annotations 

25 

26from . import __ 

27 

28 

29_scribe = __.produce_scribe( __name__ ) 

30 

31 

32def discover_editor( ) -> __.cabc.Callable[ [ str ], str ]: 

33 ''' Discovers editor and returns executor function. ''' 

34 from shutil import which 

35 from subprocess import run # nosec B404 

36 editor = ( 

37 __.os.environ.get( 'VISUAL' ) 

38 or __.os.environ.get( 'EDITOR' ) 

39 # TODO: Better default for Windows. 

40 or 'nano' ) 

41 # TODO: Platform-specific list. 

42 for editor_ in ( editor, 'nano' ): 

43 if which( editor_ ): 

44 editor = editor_ 

45 break 

46 else: editor = '' 

47 

48 if editor: 

49 

50 # TODO? async 

51 def editor_executor( filename: str ) -> str: 

52 ''' Executes editor with file. ''' 

53 run( ( editor, filename ), check = True ) # nosec B603 

54 with open( filename, 'r', encoding = 'utf-8' ) as stream: 

55 return stream.read( ) 

56 

57 return editor_executor 

58 

59 from .exceptions import ProgramAbsenceError 

60 raise ProgramAbsenceError( 'editor' ) 

61 

62 

63def edit_content( 

64 content: str = '', *, 

65 suffix: str = '.md', 

66 editor_discoverer: __.cabc.Callable[ 

67 [ ], __.cabc.Callable[ [ str ], str ] ] = discover_editor, 

68) -> str: 

69 ''' Edits content via discovered editor. ''' 

70 from .exceptions import EditorFailure, ProgramAbsenceError 

71 try: editor = editor_discoverer( ) 

72 except ProgramAbsenceError: 

73 _scribe.exception( "Could not find editor program." ) 

74 return content 

75 import tempfile 

76 with tempfile.NamedTemporaryFile( mode = 'r+', suffix = suffix ) as tmp: 

77 tmp.write( content ) 

78 tmp.flush( ) 

79 try: return editor( tmp.name ) 

80 except Exception as exc: raise EditorFailure( cause = exc ) from exc