mirror of
https://github.com/LazoCoder/Pokemon-Terminal
synced 2024-11-23 04:13:20 +00:00
Implement automatic discovery of terminal adapters
This commit is contained in:
parent
3312d54809
commit
71a341ca1c
14 changed files with 150 additions and 126 deletions
|
@ -178,7 +178,7 @@ Alternatively, you can delete images from this folder and it will not break the
|
|||
$ sudo apt-get update
|
||||
$ sudo apt install terminology
|
||||
```
|
||||
* If you get the error `39:46: syntax error: Expected end of line but found identifier. (-2741)`: Locate the file `ITerm.py` in `pokemonterminal/adapter/implementations` and on line 7, change `iTerm` to `iTerm2`. If you still experience the error, try changing it to `iTerm 2`.
|
||||
* If you get the error `39:46: syntax error: Expected end of line but found identifier. (-2741)`: Locate the file `ITerm.py` in `pokemonterminal/terminal/adapters` and on line 9, change `iTerm` to `iTerm2`. If you still experience the error, try changing it to `iTerm 2`.
|
||||
|
||||
## Saving
|
||||
|
||||
|
|
|
@ -1,24 +0,0 @@
|
|||
from pokemonterminal.adapter.implementations.ITerm import ITerm
|
||||
from pokemonterminal.adapter.implementations.NullAdapter import NullAdapter
|
||||
from pokemonterminal.adapter.implementations.Terminology import Terminology
|
||||
from pokemonterminal.adapter.implementations.Tilix import Tilix
|
||||
|
||||
|
||||
available_terminals = [
|
||||
Terminology,
|
||||
Tilix,
|
||||
ITerm
|
||||
]
|
||||
|
||||
|
||||
def identify():
|
||||
"""
|
||||
Identify the terminal we are using based on env vars.
|
||||
:return: A terminal adapter interface or a NullAdapter.
|
||||
:rtype: TerminalAdapterInterface
|
||||
"""
|
||||
for terminal in available_terminals:
|
||||
if terminal.is_available():
|
||||
return terminal()
|
||||
|
||||
return NullAdapter()
|
|
@ -1,22 +0,0 @@
|
|||
class TerminalAdapterInterface(object):
|
||||
@staticmethod
|
||||
def is_available():
|
||||
"""
|
||||
:return: True if the environment implies we are using this terminal.
|
||||
:rtype bool
|
||||
"""
|
||||
raise NotImplementedError()
|
||||
|
||||
def set_image_file_path(self, image_file_path):
|
||||
"""
|
||||
Set the background image of the terminal.
|
||||
:param image_file_path: Path to an image file.
|
||||
:rtype str
|
||||
"""
|
||||
raise NotImplementedError()
|
||||
|
||||
def clear(self):
|
||||
"""
|
||||
Clear the terminal's background image.
|
||||
"""
|
||||
raise NotImplementedError()
|
|
@ -1,33 +0,0 @@
|
|||
import os
|
||||
import subprocess
|
||||
|
||||
from pokemonterminal.adapter.base import TerminalAdapterInterface
|
||||
|
||||
|
||||
# OSA script that will change the terminal background image
|
||||
osa_script_fmt = """tell application "iTerm"
|
||||
\ttell current session of current window
|
||||
\t\tset background image to "{}"
|
||||
\tend tell
|
||||
end tell"""
|
||||
|
||||
|
||||
class ITerm(TerminalAdapterInterface):
|
||||
@staticmethod
|
||||
def is_available():
|
||||
return os.environ.get("ITERM_PROFILE")
|
||||
|
||||
def __run_osascript(self, stream):
|
||||
p = subprocess.Popen(['osascript'], stdout=subprocess.PIPE,
|
||||
stdin=subprocess.PIPE)
|
||||
p.stdin.write(stream)
|
||||
p.communicate()
|
||||
p.stdin.close()
|
||||
|
||||
def set_image_file_path(self, image_file_path):
|
||||
stdin = osa_script_fmt.format(image_file_path)
|
||||
self.__run_osascript(str.encode(stdin))
|
||||
|
||||
def clear(self):
|
||||
stdin = osa_script_fmt.format("")
|
||||
self.__run_osascript(str.encode(stdin))
|
|
@ -1,15 +0,0 @@
|
|||
from pokemonterminal.adapter.base import TerminalAdapterInterface
|
||||
|
||||
|
||||
class NullAdapter(TerminalAdapterInterface):
|
||||
err = "This terminal emulator is not supported."
|
||||
|
||||
@staticmethod
|
||||
def is_available():
|
||||
return True
|
||||
|
||||
def set_image_file_path(self, image_file_path):
|
||||
print(self.err)
|
||||
|
||||
def clear(self):
|
||||
print(self.err)
|
|
@ -1,15 +0,0 @@
|
|||
import os
|
||||
|
||||
from pokemonterminal.adapter.base import TerminalAdapterInterface
|
||||
|
||||
|
||||
class Terminology(TerminalAdapterInterface):
|
||||
@staticmethod
|
||||
def is_available():
|
||||
return os.environ.get("TERMINOLOGY") == '1'
|
||||
|
||||
def set_image_file_path(self, image_file_path):
|
||||
os.system('tybg "{}"'.format(image_file_path))
|
||||
|
||||
def clear(self):
|
||||
os.system("tybg")
|
|
@ -1,17 +1,47 @@
|
|||
# Used for creating, running and analyzing applescript and bash scripts.
|
||||
import sys
|
||||
|
||||
from pokemonterminal.adapter import identify
|
||||
from .wallpaper import get_current_adapters
|
||||
from .terminal import get_current_terminal_adapters
|
||||
from .wallpaper import get_current_wallpaper_adapters
|
||||
|
||||
TERMINAL_PROVIDER = None
|
||||
WALLPAPER_PROVIDER = None
|
||||
|
||||
|
||||
def __init_terminal_provider():
|
||||
global TERMINAL_PROVIDER
|
||||
if TERMINAL_PROVIDER is not None:
|
||||
return
|
||||
providers = get_current_terminal_adapters()
|
||||
if len(providers) > 1:
|
||||
# All this if is really not supposed to happen at all whatsoever
|
||||
# really what kind of person has 2 simultaneous D.E???
|
||||
print("Multiple providers found select the appropriate one:")
|
||||
[print(str(x)) for x in providers]
|
||||
print("If some of these make no sense or are irrelevant please file" +
|
||||
"an issue in https://github.com/LazoCoder/Pokemon-Terminal")
|
||||
print("=> ", end='')
|
||||
inp = None
|
||||
while inp is None:
|
||||
try:
|
||||
inp = int(input())
|
||||
if inp >= len(providers):
|
||||
raise ValueError()
|
||||
except ValueError as _:
|
||||
print("Invalid number, try again!")
|
||||
TERMINAL_PROVIDER = providers[inp]
|
||||
elif len(providers) <= 0:
|
||||
print("Your terminal emulator isn't supported at this time.")
|
||||
sys.exit()
|
||||
else:
|
||||
TERMINAL_PROVIDER = providers[0]
|
||||
|
||||
|
||||
def __init_wallpaper_provider():
|
||||
global WALLPAPER_PROVIDER
|
||||
if WALLPAPER_PROVIDER is not None:
|
||||
return
|
||||
providers = get_current_adapters()
|
||||
providers = get_current_wallpaper_adapters()
|
||||
if len(providers) > 1:
|
||||
# All this if is really not supposed to happen at all whatsoever
|
||||
# really what kind of person has 2 simultaneous D.E???
|
||||
|
@ -37,18 +67,16 @@ def __init_wallpaper_provider():
|
|||
|
||||
|
||||
def clear_terminal():
|
||||
adapter = identify()
|
||||
adapter.clear()
|
||||
__init_terminal_provider()
|
||||
TERMINAL_PROVIDER.clear()
|
||||
|
||||
|
||||
def change_terminal(image_file_path):
|
||||
if not isinstance(image_file_path, str):
|
||||
print("A image path must be passed to the change terminal function.")
|
||||
return
|
||||
adapter = identify()
|
||||
if adapter is None:
|
||||
print("Terminal not supported")
|
||||
adapter.set_image_file_path(image_file_path)
|
||||
__init_terminal_provider()
|
||||
TERMINAL_PROVIDER.change_terminal(image_file_path)
|
||||
|
||||
|
||||
def change_wallpaper(image_file_path):
|
||||
|
|
34
pokemonterminal/terminal/__init__.py
Normal file
34
pokemonterminal/terminal/__init__.py
Normal file
|
@ -0,0 +1,34 @@
|
|||
import os
|
||||
import importlib
|
||||
import inspect
|
||||
from .adapters import TerminalProvider
|
||||
|
||||
|
||||
def _is_adapter(member) -> bool:
|
||||
return (inspect.isclass(member)
|
||||
and issubclass(member, TerminalProvider)
|
||||
and member != TerminalProvider)
|
||||
|
||||
|
||||
def _get_adapter_classes() -> [TerminalProvider]:
|
||||
"""
|
||||
This methods reads all the modules in the adapters folder searching for
|
||||
all the implementing wallpaper adapter classes
|
||||
thanks for/adapted from https://github.com/cclauss/adapter_pattern/
|
||||
"""
|
||||
dirname = os.path.join(os.path.dirname(
|
||||
os.path.abspath(__file__)), 'adapters')
|
||||
adapter_classes = []
|
||||
for file_name in sorted(os.listdir(dirname)):
|
||||
root, ext = os.path.splitext(file_name)
|
||||
if ext.lower() == '.py' and not root.startswith('__'):
|
||||
module = importlib.import_module(
|
||||
'.' + root, 'pokemonterminal.terminal.adapters')
|
||||
for _, c in inspect.getmembers(module, _is_adapter):
|
||||
adapter_classes.append(c)
|
||||
return adapter_classes
|
||||
|
||||
|
||||
def get_current_terminal_adapters() -> [TerminalProvider]:
|
||||
arr = _get_adapter_classes()
|
||||
return [x for x in arr if x.is_compatible()]
|
31
pokemonterminal/terminal/adapters/ITerm.py
Normal file
31
pokemonterminal/terminal/adapters/ITerm.py
Normal file
|
@ -0,0 +1,31 @@
|
|||
import os
|
||||
import subprocess
|
||||
|
||||
from . import TerminalProvider as _TProv
|
||||
|
||||
|
||||
class ITerm(_TProv):
|
||||
# OSA script that will change the terminal background image
|
||||
osa_script_fmt = """tell application "iTerm"
|
||||
\ttell current session of current window
|
||||
\t\tset background image to "{}"
|
||||
\tend tell
|
||||
end tell"""
|
||||
|
||||
def is_compatible() -> bool:
|
||||
return os.environ.get("ITERM_PROFILE")
|
||||
|
||||
def __run_osascript(stream):
|
||||
p = subprocess.Popen(['osascript'], stdout=subprocess.PIPE,
|
||||
stdin=subprocess.PIPE)
|
||||
p.stdin.write(stream)
|
||||
p.communicate()
|
||||
p.stdin.close()
|
||||
|
||||
def change_terminal(self, path: str):
|
||||
stdin = self.osa_script_fmt.format(path)
|
||||
self.__run_osascript(str.encode(stdin))
|
||||
|
||||
def clear(self):
|
||||
stdin = self.osa_script_fmt.format("")
|
||||
self.__run_osascript(str.encode(stdin))
|
14
pokemonterminal/terminal/adapters/Terminology.py
Normal file
14
pokemonterminal/terminal/adapters/Terminology.py
Normal file
|
@ -0,0 +1,14 @@
|
|||
import os
|
||||
|
||||
from . import TerminalProvider as _TProv
|
||||
|
||||
|
||||
class Terminology(_TProv):
|
||||
def is_compatible() -> bool:
|
||||
return os.environ.get("TERMINOLOGY") == '1'
|
||||
|
||||
def change_terminal(path: str):
|
||||
os.system('tybg "{}"'.format(path))
|
||||
|
||||
def clear():
|
||||
os.system("tybg")
|
|
@ -1,21 +1,20 @@
|
|||
import os
|
||||
|
||||
from pokemonterminal.adapter.base import TerminalAdapterInterface
|
||||
from . import TerminalProvider as _TProv
|
||||
|
||||
|
||||
class Tilix(TerminalAdapterInterface):
|
||||
class Tilix(_TProv):
|
||||
setting_key = "com.gexperts.Tilix.Settings"
|
||||
setting_field = "background-image"
|
||||
|
||||
@staticmethod
|
||||
def is_available():
|
||||
def is_compatible() -> bool:
|
||||
return "TILIX_ID" in os.environ
|
||||
|
||||
def set_image_file_path(self, image_file_path):
|
||||
def change_terminal(self, path: str):
|
||||
command = 'gsettings set {} {} "{}"'
|
||||
os.system(command.format(self.setting_key,
|
||||
self.setting_field,
|
||||
image_file_path))
|
||||
path))
|
||||
|
||||
def clear(self):
|
||||
command = 'gsettings set {} {}'
|
27
pokemonterminal/terminal/adapters/__init__.py
Normal file
27
pokemonterminal/terminal/adapters/__init__.py
Normal file
|
@ -0,0 +1,27 @@
|
|||
class TerminalProvider:
|
||||
"""
|
||||
Interface representing all the different terminal emulators supported
|
||||
by pokemon-terminal if you want to implement a TE, create a module in this
|
||||
folder that implements this interface, reflection will do the rest.
|
||||
"""
|
||||
|
||||
def change_terminal(path: str):
|
||||
"""
|
||||
This sets the wallpaper of the corresponding TE of this adapter.
|
||||
:param path The full path of the required pokemon image
|
||||
"""
|
||||
raise NotImplementedError()
|
||||
|
||||
def is_compatible() -> bool:
|
||||
"""
|
||||
checks for compatibility
|
||||
:return a boolean saying whether or not the current adaptor is
|
||||
compatible with the running TE
|
||||
"""
|
||||
raise NotImplementedError()
|
||||
|
||||
def clear(self):
|
||||
"""
|
||||
Clear the terminal's background image.
|
||||
"""
|
||||
raise NotImplementedError()
|
|
@ -29,6 +29,6 @@ def _get_adapter_classes() -> [WallpaperProvider]:
|
|||
return adapter_classes
|
||||
|
||||
|
||||
def get_current_adapters() -> [WallpaperProvider]:
|
||||
def get_current_wallpaper_adapters() -> [WallpaperProvider]:
|
||||
arr = _get_adapter_classes()
|
||||
return [x for x in arr if x.is_compatible()]
|
||||
|
|
Loading…
Reference in a new issue