mirror of
https://github.com/LazoCoder/Pokemon-Terminal
synced 2024-11-26 22:00: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-get update
|
||||||
$ sudo apt install terminology
|
$ 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
|
## 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.
|
# Used for creating, running and analyzing applescript and bash scripts.
|
||||||
import sys
|
import sys
|
||||||
|
|
||||||
from pokemonterminal.adapter import identify
|
from .terminal import get_current_terminal_adapters
|
||||||
from .wallpaper import get_current_adapters
|
from .wallpaper import get_current_wallpaper_adapters
|
||||||
|
|
||||||
|
TERMINAL_PROVIDER = None
|
||||||
WALLPAPER_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():
|
def __init_wallpaper_provider():
|
||||||
global WALLPAPER_PROVIDER
|
global WALLPAPER_PROVIDER
|
||||||
if WALLPAPER_PROVIDER is not None:
|
if WALLPAPER_PROVIDER is not None:
|
||||||
return
|
return
|
||||||
providers = get_current_adapters()
|
providers = get_current_wallpaper_adapters()
|
||||||
if len(providers) > 1:
|
if len(providers) > 1:
|
||||||
# All this if is really not supposed to happen at all whatsoever
|
# All this if is really not supposed to happen at all whatsoever
|
||||||
# really what kind of person has 2 simultaneous D.E???
|
# really what kind of person has 2 simultaneous D.E???
|
||||||
|
@ -37,18 +67,16 @@ def __init_wallpaper_provider():
|
||||||
|
|
||||||
|
|
||||||
def clear_terminal():
|
def clear_terminal():
|
||||||
adapter = identify()
|
__init_terminal_provider()
|
||||||
adapter.clear()
|
TERMINAL_PROVIDER.clear()
|
||||||
|
|
||||||
|
|
||||||
def change_terminal(image_file_path):
|
def change_terminal(image_file_path):
|
||||||
if not isinstance(image_file_path, str):
|
if not isinstance(image_file_path, str):
|
||||||
print("A image path must be passed to the change terminal function.")
|
print("A image path must be passed to the change terminal function.")
|
||||||
return
|
return
|
||||||
adapter = identify()
|
__init_terminal_provider()
|
||||||
if adapter is None:
|
TERMINAL_PROVIDER.change_terminal(image_file_path)
|
||||||
print("Terminal not supported")
|
|
||||||
adapter.set_image_file_path(image_file_path)
|
|
||||||
|
|
||||||
|
|
||||||
def change_wallpaper(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
|
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_key = "com.gexperts.Tilix.Settings"
|
||||||
setting_field = "background-image"
|
setting_field = "background-image"
|
||||||
|
|
||||||
@staticmethod
|
def is_compatible() -> bool:
|
||||||
def is_available():
|
|
||||||
return "TILIX_ID" in os.environ
|
return "TILIX_ID" in os.environ
|
||||||
|
|
||||||
def set_image_file_path(self, image_file_path):
|
def change_terminal(self, path: str):
|
||||||
command = 'gsettings set {} {} "{}"'
|
command = 'gsettings set {} {} "{}"'
|
||||||
os.system(command.format(self.setting_key,
|
os.system(command.format(self.setting_key,
|
||||||
self.setting_field,
|
self.setting_field,
|
||||||
image_file_path))
|
path))
|
||||||
|
|
||||||
def clear(self):
|
def clear(self):
|
||||||
command = 'gsettings set {} {}'
|
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
|
return adapter_classes
|
||||||
|
|
||||||
|
|
||||||
def get_current_adapters() -> [WallpaperProvider]:
|
def get_current_wallpaper_adapters() -> [WallpaperProvider]:
|
||||||
arr = _get_adapter_classes()
|
arr = _get_adapter_classes()
|
||||||
return [x for x in arr if x.is_compatible()]
|
return [x for x in arr if x.is_compatible()]
|
||||||
|
|
Loading…
Reference in a new issue