diff --git a/.gitignore b/.gitignore index 2a162d0b9..0d76ccbd9 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,10 @@ +# Packaging +package/dist +package/build +package/_vendored +package/Output +package/inno_complie_script.iss + # Byte-compiled / optimized / DLL files __pycache__/ *.py[cod] @@ -31,7 +38,6 @@ MANIFEST # Usually these files are written by a python script from a template # before PyInstaller builds the exe, so as to inject date/other infos into it. *.manifest -*.spec # Installer logs pip-log.txt diff --git a/datashuttle/tui_launcher.py b/datashuttle/tui_launcher.py index f98f4b0be..d54d83358 100644 --- a/datashuttle/tui_launcher.py +++ b/datashuttle/tui_launcher.py @@ -42,4 +42,7 @@ def main() -> None: if __name__ == "__main__": - main() + try: + main() + except: + input("hello") diff --git a/datashuttle/utils/rclone.py b/datashuttle/utils/rclone.py index d71c59cf7..03310145f 100644 --- a/datashuttle/utils/rclone.py +++ b/datashuttle/utils/rclone.py @@ -12,6 +12,7 @@ import platform import shlex import subprocess +import sys import tempfile from subprocess import CompletedProcess @@ -19,6 +20,22 @@ from datashuttle.utils import utils +def get_command(command: str) -> str: + """ """ + if getattr(sys, "frozen", False): + # PyInstaller: binary extracted to _MEIPASS + + if sys.platform == "win32": + format_command = f'"{sys._MEIPASS}/rclone.exe" {command}' + else: + format_command = f"{sys._MEIPASS}/rclone {command}" + else: + # Normal Python execution: use PATH or fixed path + format_command = f"rclone {command}" # or provide full path if needed + + return format_command + + def call_rclone(command: str, pipe_std: bool = False) -> CompletedProcess: """Call rclone with the specified command. @@ -35,13 +52,17 @@ def call_rclone(command: str, pipe_std: bool = False) -> CompletedProcess: subprocess.CompletedProcess with `stdout` and `stderr` attributes. """ - command = "rclone " + command + format_command = get_command(command) + if pipe_std: output = subprocess.run( - command, stdout=subprocess.PIPE, stderr=subprocess.PIPE, shell=True + format_command, + stdout=subprocess.PIPE, + stderr=subprocess.PIPE, + shell=True, ) else: - output = subprocess.run(command, shell=True) + output = subprocess.run(format_command, shell=True) return output @@ -64,18 +85,18 @@ def call_rclone_through_script(command: str) -> CompletedProcess: """ system = platform.system() - command = "rclone " + command - if system == "Windows": suffix = ".bat" else: suffix = ".sh" command = "#!/bin/bash\n" + command + format_command = get_command(command) + with tempfile.NamedTemporaryFile( mode="w", suffix=suffix, delete=False ) as tmp_script: - tmp_script.write(command) + tmp_script.write(format_command) tmp_script_path = tmp_script.name try: diff --git a/package/NeuroBlueprint_icon.ico b/package/NeuroBlueprint_icon.ico new file mode 100644 index 000000000..3f5fc6635 Binary files /dev/null and b/package/NeuroBlueprint_icon.ico differ diff --git a/package/datashuttle.spec b/package/datashuttle.spec new file mode 100644 index 000000000..f42f0330d --- /dev/null +++ b/package/datashuttle.spec @@ -0,0 +1,79 @@ +# main.spec +# -*- mode: python ; coding: utf-8 -*- +import os +import sys +import platform +from glob import glob +from pathlib import Path + +# Include .tcss files +tcss_files = [ + (f, os.path.join("datashuttle", "tui", "css")) + for f in glob("../datashuttle/tui/css/*.tcss") +] + +# Get current conda environment prefix +env_prefix = sys.prefix + +# Detect OS and set rclone path +if platform.system() == "Windows": + rclone_src = os.path.join(env_prefix, "bin", "rclone.exe") +else: + rclone_src = os.path.join(env_prefix, "bin", "rclone") + +# Verify rclone exists +if not os.path.isfile(rclone_src): + raise FileNotFoundError(f"rclone binary not found at: {rclone_src}") + +# Add rclone as a binary to be bundled +binaries = [(rclone_src, '.')] + +a = Analysis( + ['datashuttle_launcher.py'], # terminal_launcher + pathex=[os.path.abspath('..')], + binaries=binaries, + datas=tcss_files, + hiddenimports=[ + 'datashuttle.tui_launcher', + 'datashuttle.tui.app', + 'textual.widgets._tab_pane', + 'textual.widgets._input', + 'textual.widgets._tree_control', + ], + hookspath=['hooks'], + hooksconfig={}, + runtime_hooks=[], + excludes=[], + noarchive=False, + optimize=0, +) + +pyz = PYZ(a.pure) + +exe = EXE( + pyz, + a.scripts, + [], + exclude_binaries=True, + name='datashuttle', + debug=False, + bootloader_ignore_signals=False, + strip=False, + upx=True, + console=True, + disable_windowed_traceback=False, + argv_emulation=False, + target_arch=None, + codesign_identity=None, + entitlements_file=None, +) + +coll = COLLECT( + exe, + a.binaries, + a.datas, + strip=False, + upx=True, + upx_exclude=[], + name='datashuttle' +) diff --git a/package/datashuttle_launcher.py b/package/datashuttle_launcher.py new file mode 100644 index 000000000..b3dd46e22 --- /dev/null +++ b/package/datashuttle_launcher.py @@ -0,0 +1,24 @@ +import sys +from pathlib import Path + +# Add project root to sys.path +project_root = Path(__file__).resolve().parent.parent +sys.path.insert(0, str(project_root)) + +# Import main from tui_launcher +from datashuttle.tui_launcher import main as datashuttle_main + + +def run(): + # Simulate: datashuttle launch + sys.argv = ["datashuttle", "launch"] + datashuttle_main() + + +if __name__ == "__main__": + try: + run() + except Exception as e: + print(f"\nError: {e}") + finally: + input("\nPress Enter to exit...") diff --git a/package/license.txt b/package/license.txt new file mode 100644 index 000000000..3b18e512d --- /dev/null +++ b/package/license.txt @@ -0,0 +1 @@ +hello world diff --git a/package/notes.txt b/package/notes.txt new file mode 100644 index 000000000..224985c3e --- /dev/null +++ b/package/notes.txt @@ -0,0 +1,4 @@ +TODO: +1) write package script for macOS and organise code and outputs properly. +2) go back to windows and rework everything +3) text on linux diff --git a/package/package_linux.py b/package/package_linux.py new file mode 100644 index 000000000..ef403cdb3 --- /dev/null +++ b/package/package_linux.py @@ -0,0 +1,73 @@ +import shutil +import subprocess +from pathlib import Path + +import packaging_utils + +WEZTERM_VERSION = packaging_utils.get_wezterm_version() +WEZTERM_FOLDERNAME = f"WezTerm-{WEZTERM_VERSION}-Ubuntu20.04.AppImage" +WEZTERM_URL = f"https://github.com/wezterm/wezterm/releases/download/{WEZTERM_VERSION}/{WEZTERM_FOLDERNAME}.zip" + +# Paths +project_root = Path(__file__).parent +vendored_dir = project_root / "_vendored" + +if not (vendored_dir / WEZTERM_FOLDERNAME).exists(): + packaging_utils.download_wezterm(vendored_dir, WEZTERM_FOLDERNAME) + +if (build_path := project_root / "build").exists(): + shutil.rmtree(build_path) + +if (dist_path := project_root / "dist").exists(): + shutil.rmtree(dist_path) + +# Step 2: Run PyInstaller builds +subprocess.run(f"pyinstaller {project_root / 'datashuttle.spec'}", shell=True) +subprocess.run( + f"pyinstaller {project_root / 'terminal_launcher_windows.spec'}", + shell=True, +) + +# Paths +dist_dir = project_root / "dist" +launcher_subdir = dist_dir / "terminal_launcher_" + +shutil.move(dist_dir / "terminal_launcher", launcher_subdir) + +# Copy contents of dist/terminal_launcher/ into dist/ +for item in launcher_subdir.iterdir(): + dest = dist_dir / item.name + if item.is_dir(): + if dest.exists(): + shutil.rmtree(dest) + shutil.copytree(item, dest) + else: + shutil.copy2(item, dest) + + +# TODO COPY LICENSE + +shutil.rmtree(launcher_subdir) + +vendored_output_path = dist_dir / "_vendored" / "squashfs-root" + +shutil.copytree( + vendored_dir / "squashfs-root", + vendored_output_path, + dirs_exist_ok=True, + symlinks=True, + copy_function=shutil.copy2, +) + +shutil.copy(vendored_dir / WEZTERM_FOLDERNAME, vendored_output_path.parent) + + +shutil.copy( + project_root / "license.txt", dist_dir +) # TODO: NEED TO DO THIS FOR ALL +shutil.copy(project_root / "NeuroBlueprint_icon.ico", dist_dir) + +shutil.copy( + project_root / "wezterm_config.lua", + vendored_output_path, +) diff --git a/package/package_macos.py b/package/package_macos.py new file mode 100644 index 000000000..2919cf762 --- /dev/null +++ b/package/package_macos.py @@ -0,0 +1,52 @@ +import shutil +import subprocess +from pathlib import Path + +import packaging_utils + +WEZTERM_VERSION = packaging_utils.get_wezterm_version() +WEZTERM_FOLDERNAME = f"WezTerm-macos-{WEZTERM_VERSION}" +WEZTERM_URL = f"https://github.com/wezterm/wezterm/releases/download/{WEZTERM_VERSION}/{WEZTERM_FOLDERNAME}.zip" + +# Paths +project_root = Path(__file__).parent +vendored_dir = project_root / "_vendored" + +if not (vendored_dir / WEZTERM_FOLDERNAME).exists(): + packaging_utils.download_wezterm(vendored_dir, WEZTERM_FOLDERNAME) + +if (build_path := project_root / "build").exists(): + shutil.rmtree(build_path) + +if (dist_path := project_root / "dist").exists(): + shutil.rmtree(dist_path) + +# Step 2: Run PyInstaller builds +subprocess.run(f"pyinstaller {project_root / 'datashuttle.spec'}", shell=True) +subprocess.run( + f"pyinstaller {project_root / 'terminal_launcher_macos.spec'}", shell=True +) + +app_macos_path = ( + project_root / "dist" / "Datashuttle.app" / "Contents" / "Resources" +) + +shutil.copytree( + vendored_dir / f"{WEZTERM_FOLDERNAME}", + app_macos_path / "_vendored" / f"{WEZTERM_FOLDERNAME}", +) + +shutil.copytree( + project_root / "dist" / "datashuttle" / "_internal", + app_macos_path.parent / "Resources" / "_internal", +) + +shutil.copy( + project_root / "dist" / "datashuttle" / "datashuttle", + app_macos_path.parent / "Resources", +) + +shutil.copy( + project_root / "wezterm_config.lua", + app_macos_path.parent / "Resources" / "_vendored" / WEZTERM_FOLDERNAME, +) diff --git a/package/package_windows.py b/package/package_windows.py new file mode 100644 index 000000000..27386d1b1 --- /dev/null +++ b/package/package_windows.py @@ -0,0 +1,164 @@ +import shutil +import subprocess +from pathlib import Path + +import packaging_utils + +# ---------------------------------------------------------------------------------------------------------------------- +# Windows - Inno Setup +# ---------------------------------------------------------------------------------------------------------------------- + + +def make_inno_setup_script(version, base_path): + """{} are required in text so easier to use this method""" + file_body = ( + r""" + ; Script generated by the Inno Setup Script Wizard. + ; SEE THE DOCUMENTATION FOR DETAILS ON CREATING INNO SETUP SCRIPT FILES! + + #define MyAppName "Datashuttle" + #define MyAppVersion """ + + '"' + + version + + """" + #define MyAppPublisher "Neuroinformatics Unit, Sainsbury Wellcome Centre, London, UK." + #define MyAppURL "www.datashuttle.neuroinformatics.dev" + #define MyAppExeName "terminal_launcher.exe" + + [Setup] + ; NOTE: The value of AppId uniquely identifies this application. Do not use the same AppId value in installers for other applications. + ; (To generate a new GUID, click Tools | Generate GUID inside the IDE.) + AppId={{D063D197-9D21-426B-BF8C-D5612C74DF15} + AppName={#MyAppName} + AppVersion={#MyAppVersion} + ;AppVerName={#MyAppName} {#MyAppVersion} + AppPublisher={#MyAppPublisher} + AppPublisherURL={#MyAppURL} + AppSupportURL={#MyAppURL} + AppUpdatesURL={#MyAppURL} + DefaultDirName={autopf}\DataShuttle + DisableProgramGroupPage=yes + LicenseFile=""" + + base_path + + """\dist\license.txt + ; Uncomment the following line to run in non administrative install mode (install for current user only.) + ;PrivilegesRequired=lowest + PrivilegesRequiredOverridesAllowed=dialog + OutputBaseFilename=datashuttle_""" + + version + + """ + SetupIconFile=""" + + base_path + + r"""\dist\NeuroBlueprint_icon.ico + UninstallDisplayIcon={app}\NeuroBlueprint_icon.ico + Compression=lzma + SolidCompression=yes + WizardStyle=modern + + [Languages] + Name: "english"; MessagesFile: "compiler:Default.isl" + + [Tasks] + Name: "desktopicon"; Description: "{cm:CreateDesktopIcon}"; GroupDescription: "{cm:AdditionalIcons}"; Flags: unchecked + + [Files] + Source: """ + + '"' + + base_path + + r"""\dist\terminal_launcher.exe"; DestDir: "{app}"; Flags: ignoreversion + Source: """ + + '"' + + base_path + + """\dist\*"; DestDir: "{app}"; Flags: ignoreversion recursesubdirs createallsubdirs + ; NOTE: Don't use "Flags: ignoreversion" on any shared system files + + [Icons] + Name: "{autoprograms}\{#MyAppName}"; Filename: "{app}\{#MyAppExeName}" + Name: "{autodesktop}\{#MyAppName}"; Filename: "{app}\{#MyAppExeName}"; Tasks: desktopicon + + [Run] + Filename: "{app}\{#MyAppExeName}"; Description: "{cm:LaunchProgram,{#StringChange(MyAppName, '&', '&&')}}"; Flags: nowait postinstall skipifsilent + """ + ) + + return file_body + + +# Constants +WEZTERM_VERSION = packaging_utils.get_wezterm_version() +WEZTERM_FOLDERNAME = f"WezTerm-windows-{WEZTERM_VERSION}" +WEZTERM_URL = f"https://github.com/wezterm/wezterm/releases/download/{WEZTERM_VERSION}/{WEZTERM_FOLDERNAME}.zip" + +# Paths +project_root = Path(__file__).parent +vendored_dir = project_root / "_vendored" + +if not (vendored_dir / WEZTERM_FOLDERNAME).exists(): + packaging_utils.download_wezterm(vendored_dir, WEZTERM_FOLDERNAME) + +if (build_path := project_root / "build").exists(): + shutil.rmtree(build_path) + +if (dist_path := project_root / "dist").exists(): + shutil.rmtree(dist_path) + +# Step 2: Run PyInstaller builds +subprocess.run(f"pyinstaller {project_root / 'datashuttle.spec'}", shell=True) +subprocess.run( + f"pyinstaller {project_root / 'terminal_launcher_windows.spec'}", + shell=True, +) + + +# Paths +dist_dir = project_root / "dist" +launcher_subdir = dist_dir / "terminal_launcher" + +# Copy contents of dist/terminal_launcher/ into dist/ +for item in launcher_subdir.iterdir(): + dest = dist_dir / item.name + if item.is_dir(): + if dest.exists(): + shutil.rmtree(dest) + shutil.copytree(item, dest) + else: + shutil.copy2(item, dest) + +# Optional: Remove the now-empty terminal_launcher folder +shutil.rmtree(launcher_subdir) + + +# Step 3: Copy WezTerm into dist/_vendored +terminal_launcher_dist_dir = dist_dir / "terminal_launcher" +vendored_output_path = dist_dir / "_vendored" / WEZTERM_FOLDERNAME + +shutil.copytree( + vendored_dir / WEZTERM_FOLDERNAME, vendored_output_path, dirs_exist_ok=True +) + +shutil.copy( + project_root / "license.txt", dist_dir +) # TODO: NEED TO DO THIS FOR ALL +shutil.copy(project_root / "NeuroBlueprint_icon.ico", dist_dir) + +shutil.copy( + project_root / "wezterm_config.lua", + project_root / "dist" / "_vendored" / WEZTERM_FOLDERNAME, +) + +import os + +inno_path = project_root / "inno_complie_script.iss" + +if os.path.isfile(inno_path): + os.remove(inno_path) +f = open(inno_path, "a") + +text = make_inno_setup_script("0.0.0", str(project_root)) # TODO: version + +f.write(text.strip()) +f.close() + +# TODO: set up downloader + +subprocess.call(rf"C:\Program Files (x86)\Inno Setup 6\iscc {inno_path}") diff --git a/package/packaging_utils.py b/package/packaging_utils.py new file mode 100644 index 000000000..a560d7db1 --- /dev/null +++ b/package/packaging_utils.py @@ -0,0 +1,61 @@ +import subprocess +import zipfile +from sys import platform + +import requests + + +def get_wezterm_version(): + return "20240203-110809-5046fc22" + + +def download_wezterm(vendored_dir, wezterm_foldername): + """ """ + wezterm_url = f"https://github.com/wezterm/wezterm/releases/download/{get_wezterm_version()}/{wezterm_foldername}" # .zip TODO + print(wezterm_url) + + wezterm_extracted_dir = vendored_dir / wezterm_foldername + wezterm_zip_path = vendored_dir / f"{wezterm_foldername}" # .zip" + + # Step 1: Download and extract WezTerm if missing + if not wezterm_extracted_dir.exists(): + print("⬇ Downloading WezTerm...") + vendored_dir.mkdir(parents=True, exist_ok=True) + response = requests.get(wezterm_url) + response.raise_for_status() + + with open(wezterm_zip_path, "wb") as f: + f.write(response.content) + + print(wezterm_zip_path) + breakpoint() + + print("📦 Extracting WezTerm with system unzip...") + + if platform == "darwin": ## TODO always use same way + subprocess.run( + [ + "unzip", + "-q", + str(wezterm_zip_path), + "-d", + str(vendored_dir), + ], + check=True, + ) + elif platform == "linux": + import os + + os.chdir(vendored_dir) + subprocess.run( + f"chmod +x {wezterm_zip_path}; {wezterm_zip_path} --appimage-extract", + shell=True, + ) + else: + with zipfile.ZipFile(wezterm_zip_path, "r") as zip_ref: + zip_ref.extractall(vendored_dir) + + wezterm_zip_path.unlink() # Optional: clean up ZIP + print("✅ WezTerm ready.") + else: + print("✅ WezTerm already present. Skipping download.") diff --git a/package/terminal_launcher.py b/package/terminal_launcher.py new file mode 100644 index 000000000..e78edc2bb --- /dev/null +++ b/package/terminal_launcher.py @@ -0,0 +1,90 @@ +# pyinstaller/run_in_terminal.py + +import os +import platform +import subprocess +import sys +from pathlib import Path + +import packaging_utils + + +def main(): + print("RUNNING") + + WEZTERM_VERSION = packaging_utils.get_wezterm_version() + + print("WEZTERM_VERSION", WEZTERM_VERSION) + + if platform.system() == "Windows": + if getattr(sys, "frozen", False): + # Running as a bundled executable + base_path = Path(sys.executable).parent + else: + # Running as a script + base_path = Path(__file__).resolve().parent + + wezterm_path = ( + Path(__file__).parent.parent + / f"_vendored\WezTerm-windows-{WEZTERM_VERSION}" + ) + wezterm_exe_path = wezterm_path / "wezterm-gui.exe" + wezterm_config_path = wezterm_path / "wezterm_config.lua" + exe = base_path / "datashuttle" / "datashuttle.exe" + + elif platform.system() == "Darwin": + # This is a hot mess, almost direct copy from above. + if getattr(sys, "frozen", False): + # Running as a bundled executable + base_path = Path(sys.executable).parent.parent / "Resources" + else: + # Running as a script + base_path = Path(__file__).resolve().parent.parent + + wezterm_path = base_path / f"_vendored/WezTerm-macos-{WEZTERM_VERSION}" + wezterm_exe_path = ( + wezterm_path / "Wezterm.app/Contents/MacOS/wezterm-gui" + ) + wezterm_config_path = wezterm_path / "wezterm_config.lua" + + exe = base_path / "datashuttle" + + elif platform.system() == "Linux": + base_path = Path(__file__).resolve().parent.parent + print(base_path) + + wezterm_exe_path = base_path / "_vendored/squashfs-root/AppRun" + + wezterm_config_path = wezterm_path / "wezterm_config.lua" + + exe = base_path / "datashuttle" + + # https://github.com/wezterm/wezterm/releases/download/20240203-110809-5046fc22/WezTerm-macos-20240203-110809-5046fc22.zip + + print("BaSE PATH", base_path) + print("CWD", os.getcwd()) + print("HELLO WORLD") + print("EXE", exe) + print("TERMINAL EXE", wezterm_exe_path) + print("CONFIG", wezterm_config_path.as_posix()) + + system = platform.system() + + env = os.environ.copy() + env["WEZTERM_CONFIG_FILE"] = str(wezterm_config_path.as_posix()) + + if system == "Windows": + cmd = f'"{wezterm_exe_path}" start -- "{exe}"' + + subprocess.Popen(cmd, shell=True, env=env) + + elif system == "Darwin": + cmd = f"""{wezterm_exe_path} start -- sh -c 'echo "Starting datashuttle..."; "{exe}"'""" + + subprocess.Popen(cmd, shell=True, env=env) + else: + subprocess.run(exe) + + +if __name__ == "__main__": + main() diff --git a/package/terminal_launcher_macos.spec b/package/terminal_launcher_macos.spec new file mode 100644 index 000000000..7a5a39878 --- /dev/null +++ b/package/terminal_launcher_macos.spec @@ -0,0 +1,63 @@ +# -*- mode: python ; coding: utf-8 -*- + +a = Analysis( + ['terminal_launcher.py'], + pathex=[], + binaries=[], + datas=[], + hiddenimports=[], + hookspath=[], + hooksconfig={}, + runtime_hooks=[], + excludes=[], + noarchive=False, + optimize=0, +) +pyz = PYZ(a.pure) + +exe = EXE( + pyz, + a.scripts, + [], + exclude_binaries=True, + name='terminal_launcher', + debug=False, + bootloader_ignore_signals=False, + strip=False, + upx=True, + console=False, + disable_windowed_traceback=False, + argv_emulation=False, + target_arch=None, + codesign_identity=None, + entitlements_file=None, +) + +coll = COLLECT( + exe, + a.binaries, + a.datas, + strip=False, + upx=True, + upx_exclude=[], + name='terminal_launcher', +) + +app = BUNDLE( + exe, + a.binaries, + a.datas, + name='datashuttle.app', # <- the app bundle name + icon=None, # <- optional .icns file here + bundle_identifier="com.yourdomain.terminal_launcher", # optional + info_plist={ + 'NSHighResolutionCapable': 'True', + 'CFBundleDisplayName': 'Datashuttle', + 'CFBundleName': 'Datashuttle', + 'CFBundleIdentifier': 'com.yourdomain.datashuttle', + 'CFBundleVersion': '0.1.0', + 'CFBundleShortVersionString': '0.1.0', + 'NSPrincipalClass': 'NSApplication', + 'LSMinimumSystemVersion': '10.13.0', + } +) diff --git a/package/terminal_launcher_windows.spec b/package/terminal_launcher_windows.spec new file mode 100644 index 000000000..cca74632d --- /dev/null +++ b/package/terminal_launcher_windows.spec @@ -0,0 +1,43 @@ +# -*- mode: python ; coding: utf-8 -*- + +a = Analysis( + ['terminal_launcher.py'], + pathex=[], + binaries=[], + datas=[], + hiddenimports=[], + hookspath=[], + hooksconfig={}, + runtime_hooks=[], + excludes=[], + noarchive=False, + optimize=0, +) +pyz = PYZ(a.pure) + +exe = EXE( + pyz, + a.scripts, + exclude_binaries=True, + name='terminal_launcher', + debug=False, + bootloader_ignore_signals=False, + strip=False, + upx=True, + console=False, # Set `True` for debugging + disable_windowed_traceback=False, + argv_emulation=False, + target_arch=None, + codesign_identity=None, + entitlements_file=None, +) + +coll = COLLECT( + exe, + a.binaries, + a.datas, + strip=False, + upx=True, + upx_exclude=[], + name='terminal_launcher', +) diff --git a/package/wezterm_config.lua b/package/wezterm_config.lua new file mode 100644 index 000000000..b9b6bbbb4 --- /dev/null +++ b/package/wezterm_config.lua @@ -0,0 +1,15 @@ +local wezterm = require 'wezterm' + +local config = {} + +wezterm.on("format-tab-title", function(tab, tabs, panes, config, hover, max_width) + return { + { Text = " datashuttle " }, + } +end) + +config.initial_rows = 32 +config.initial_cols = 115 +config.font_size = 12.0 + +return config