Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 12 additions & 0 deletions app/lib/window.ts
Original file line number Diff line number Diff line change
Expand Up @@ -323,6 +323,9 @@ export class Window {
this.window.on('show', () => {
this.visible.next(true)
this.send('host:window-shown')
try {
this.window.webContents.invalidate()
} catch {}
})

this.window.on('hide', () => {
Expand Down Expand Up @@ -373,6 +376,15 @@ export class Window {

this.window.on('focus', () => {
this.send('host:window-focused')
try {
this.window.webContents.invalidate()
} catch {}
})

this.window.on('restore', () => {
try {
this.window.webContents.invalidate()
} catch {}
})

this.on('ready', () => {
Expand Down
2 changes: 1 addition & 1 deletion app/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@
"tabby-terminal": "*"
},
"resolutions": {
"node-abi": "4.9.0",
"node-abi": "^3.0.0",
"node-gyp": "^10.0.0",
"nan": "2.22.2",
"node-addon-api": "^8.3.0"
Expand Down
15 changes: 5 additions & 10 deletions app/yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -2981,12 +2981,12 @@ negotiator@^0.6.3:
resolved "https://registry.yarnpkg.com/negotiator/-/negotiator-0.6.4.tgz#777948e2452651c570b712dd01c23e262713fff7"
integrity sha512-myRT3DiWPHqho5PrJaIRyaMv2kgYf0mUVgBNOYMuCH5Ki1yEiQaf/ZJuQ62nvpc44wL5WDbTX7yGJi1Neevw8w==

node-abi@4.9.0, node-abi@^3.3.0:
version "4.9.0"
resolved "https://registry.yarnpkg.com/node-abi/-/node-abi-4.9.0.tgz#ca6dabf7991e54bf3ba6d8d32641e1b84f305263"
integrity sha512-0isb3h+AXUblx5Iv0mnYy2WsErH+dk2e9iXJXdKAtS076Q5hP+scQhp6P4tvDeVlOBlG3ROKvkpQHtbORllq2A==
node-abi@^3.0.0, node-abi@^3.3.0:
version "3.87.0"
resolved "https://registry.yarnpkg.com/node-abi/-/node-abi-3.87.0.tgz#423e28fea5c2f195fddd98acded9938c001ae6dd"
integrity sha512-+CGM1L1CgmtheLcBuleyYOn7NWPVu0s0EJH2C4puxgEZb9h8QpR9G2dBfZJOAUhi7VQxuBPMd0hiISWcTyiYyQ==
dependencies:
semver "^7.6.3"
semver "^7.3.5"

node-addon-api@3.1.0, node-addon-api@6.1.0, node-addon-api@7.1.0, node-addon-api@^3.0.2, node-addon-api@^3.1.0, node-addon-api@^4.0.0, node-addon-api@^4.3.0, node-addon-api@^7.1.0, node-addon-api@^8.3.0:
version "8.3.0"
Expand Down Expand Up @@ -4054,11 +4054,6 @@ semver@^7.3.5, semver@^7.5.3:
resolved "https://registry.yarnpkg.com/semver/-/semver-7.7.3.tgz#4b5f4143d007633a8dc671cd0a6ef9147b8bb946"
integrity sha512-SdsKMrI9TdgjdweUSR9MweHA4EJ8YxHn8DFaDisvhVlUOe4BF1tLD7GAj0lIqWVl+dPb/rExr0Btby5loQm20Q==

semver@^7.6.3:
version "7.7.2"
resolved "https://registry.yarnpkg.com/semver/-/semver-7.7.2.tgz#67d99fdcd35cec21e6f8b87a7fd515a33f982b58"
integrity sha512-RF0Fw+rO5AMf9MAyaRXI4AV0Ulj5lMHqVxxdSgiVbixSCXoEmmX/jk0CuJw4+3SqroYO9VoUh+HcuJivvtJemA==

serialize-error@^5.0.0:
version "5.0.0"
resolved "https://registry.yarnpkg.com/serialize-error/-/serialize-error-5.0.0.tgz#a7ebbcdb03a5d71a6ed8461ffe0fc1a1afed62ac"
Expand Down
106 changes: 83 additions & 23 deletions scripts/build-macos.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@
/* eslint-disable @typescript-eslint/prefer-nullish-coalescing */
import { build as builder } from 'electron-builder'
import * as vars from './vars.mjs'
import { execFileSync } from 'child_process'
import * as path from 'path'

const isTag = (process.env.GITHUB_REF || '').startsWith('refs/tags/')

Expand All @@ -16,31 +18,89 @@ if (process.env.GITHUB_HEAD_REF) {
process.env.APPLE_ID ??= process.env.APPSTORE_USERNAME
process.env.APPLE_APP_SPECIFIC_PASSWORD ??= process.env.APPSTORE_PASSWORD

builder({
dir: true,
mac: ['dmg', 'zip'],
x64: process.env.ARCH === 'x86_64',
arm64: process.env.ARCH === 'arm64',
config: {
extraMetadata: {
version: vars.version,
teamId: process.env.APPLE_TEAM_ID,
},
mac: {
identity: !process.env.CI || process.env.CSC_LINK ? undefined : null,
notarize: !!process.env.APPLE_TEAM_ID,
const wantsRealSigning = !!(process.env.CSC_LINK || process.env.CSC_NAME || process.env.APPLE_TEAM_ID)

async function main () {
if (wantsRealSigning) {
await builder({
dir: true,
mac: ['dmg', 'zip'],
x64: process.env.ARCH === 'x86_64',
arm64: process.env.ARCH === 'arm64',
config: {
extraMetadata: {
version: vars.version,
teamId: process.env.APPLE_TEAM_ID,
},
mac: {
notarize: false,
},
npmRebuild: process.env.ARCH !== 'arm64',
publish: process.env.KEYGEN_TOKEN ? [
vars.keygenConfig,
{
provider: 'github',
channel: `latest-${process.env.ARCH}`,
},
] : undefined,
},
publish: (process.env.KEYGEN_TOKEN && isTag) ? 'always' : 'never',
})
return
}

await builder({
dir: true,
mac: ['dir'],
x64: process.env.ARCH === 'x86_64',
arm64: process.env.ARCH === 'arm64',
config: {
extraMetadata: {
version: vars.version,
},
mac: {
identity: null,
hardenedRuntime: false,
entitlements: null,
entitlementsInherit: null,
notarize: false,
},
npmRebuild: process.env.ARCH !== 'arm64',
publish: undefined,
},
npmRebuild: process.env.ARCH !== 'arm64',
publish: process.env.KEYGEN_TOKEN ? [
vars.keygenConfig,
{
provider: 'github',
channel: `latest-${process.env.ARCH}`,
publish: 'never',
})

const appDir = path.join(process.cwd(), 'dist', process.env.ARCH === 'x86_64' ? 'mac' : `mac-${process.env.ARCH}`)
const appPath = path.join(appDir, 'Tabby.app')

execFileSync('/usr/bin/codesign', ['--force', '--deep', '--sign', '-', appPath], { stdio: 'inherit' })
execFileSync('/usr/bin/codesign', ['--verify', '--deep', '--strict', appPath], { stdio: 'inherit' })

await builder({
prepackaged: appPath,
mac: ['dmg', 'zip'],
x64: process.env.ARCH === 'x86_64',
arm64: process.env.ARCH === 'arm64',
config: {
extraMetadata: {
version: vars.version,
},
mac: {
identity: null,
hardenedRuntime: false,
entitlements: null,
entitlementsInherit: null,
notarize: false,
},
] : undefined,
},
publish: (process.env.KEYGEN_TOKEN && isTag) ? 'always' : 'never',
}).catch(e => {
npmRebuild: false,
publish: undefined,
},
publish: 'never',
})
}

main().catch(e => {
console.error(e)
process.exit(1)
})
2 changes: 1 addition & 1 deletion tabby-core/src/components/appRoot.component.pug
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ title-bar(
[class.tabs-on-right]='hasVerticalTabs() && config.store.appearance.tabsLocation == "right"',
)
.tab-bar(
*ngIf='!hostWindow.isFullscreen || config.store.appearance.tabsInFullscreen',
*ngIf='true',
[class.tab-bar-no-controls-overlay]='hostApp.platform == Platform.macOS',
(dblclick)='!isTitleBarNeeded() && toggleMaximize()'
)
Expand Down
7 changes: 7 additions & 0 deletions tabby-core/src/components/appRoot.component.scss
Original file line number Diff line number Diff line change
Expand Up @@ -171,6 +171,13 @@ $tab-border-radius: 4px;
}
}

:host.fullscreen {
.tab-bar {
z-index: 5000;
background: #222; // ensure background is opaque so content doesn't bleed through
}
}

.content {
flex: 1 1 0;
position: relative;
Expand Down
1 change: 1 addition & 0 deletions tabby-core/src/components/appRoot.component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,7 @@ export class AppRootComponent {
@HostBinding('class.platform-win32') platformClassWindows = process.platform === 'win32'
@HostBinding('class.platform-darwin') platformClassMacOS = process.platform === 'darwin'
@HostBinding('class.platform-linux') platformClassLinux = process.platform === 'linux'
@HostBinding('class.fullscreen') get isFullscreen () { return this.hostWindow.isFullscreen }
@HostBinding('class.no-tabs') noTabs = true
@ViewChildren(TabBodyComponent) tabBodies: TabBodyComponent[]
@ViewChild('activeTransfersDropdown') activeTransfersDropdown: NgbDropdown
Expand Down
21 changes: 21 additions & 0 deletions tabby-core/src/components/splitTabSpanner.component.scss
Original file line number Diff line number Diff line change
Expand Up @@ -4,15 +4,36 @@
z-index: 5;
transition: 0.125s background;

&::after {
content: '';
position: absolute;
background: #d3d3d3;
display: block;
}

&.v {
cursor: ns-resize;
height: 10px;
margin-top: -5px;

&::after {
left: 0;
right: 0;
top: 50%;
height: 1px;
}
}

&.h {
cursor: ew-resize;
width: 10px;
margin-left: -5px;

&::after {
top: 0;
bottom: 0;
left: 50%;
width: 1px;
}
}
}
25 changes: 24 additions & 1 deletion tabby-electron/src/services/hostWindow.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ export class ElectronHostWindow extends HostWindowService {

private _isFullscreen = false
private _isMaximized = false
private repaintScheduled = false

constructor (
zone: NgZone,
Expand All @@ -31,7 +32,10 @@ export class ElectronHostWindow extends HostWindowService {
this._isFullscreen = false
}))

electron.ipcRenderer.on('host:window-shown', () => zone.run(() => this.windowShown.next()))
electron.ipcRenderer.on('host:window-shown', () => zone.run(() => {
this.windowShown.next()
this.scheduleRepaint()
}))

electron.ipcRenderer.on('host:window-close-request', () => zone.run(() => {
this.windowCloseRequest.next()
Expand All @@ -43,6 +47,7 @@ export class ElectronHostWindow extends HostWindowService {

electron.ipcRenderer.on('host:window-focused', () => zone.run(() => {
this.windowFocused.next()
this.scheduleRepaint()
}))

electron.ipcRenderer.on('host:became-main-window', () => zone.run(() => {
Expand Down Expand Up @@ -127,4 +132,22 @@ export class ElectronHostWindow extends HostWindowService {
bringToFront (): void {
this.electron.ipcRenderer.send('window-bring-to-front')
}

private scheduleRepaint (): void {
if (this.repaintScheduled) {
return
}
this.repaintScheduled = true
requestAnimationFrame(() => {
requestAnimationFrame(() => {
this.repaintScheduled = false
try {
window.dispatchEvent(new Event('resize'))
} catch {}
try {
this.getWindow().webContents.invalidate()
} catch {}
})
})
}
}
6 changes: 5 additions & 1 deletion tabby-electron/src/sftpContextMenu.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
import { Subject, debounceTime, debounce } from 'rxjs'
import { Injectable } from '@angular/core'
import { MenuItemOptions, TranslateService } from 'tabby-core'
import { SFTPFile, SFTPPanelComponent, SFTPContextMenuItemProvider, SFTPSession } from 'tabby-ssh'

Check failure on line 7 in tabby-electron/src/sftpContextMenu.ts

View workflow job for this annotation

GitHub Actions / Lint

Cannot find module 'tabby-ssh' or its corresponding type declarations.
import { ElectronPlatformService } from './services/platform.service'


Expand All @@ -31,7 +31,11 @@
]
if (!item.isDirectory) {
items.push({
click: () => this.edit(item, panel.sftp),
click: () => {
if (panel.sftp) {
this.edit(item, panel.sftp)
}
},
label: this.translate.instant('Edit locally'),
})
}
Expand Down
17 changes: 13 additions & 4 deletions tabby-local/src/session.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,15 +7,15 @@

const windowsDirectoryRegex = /([a-zA-Z]:[^\:\[\]\?\"\<\>\|]+)/mi

function mergeEnv (...envs) {
const result = {}
const keyMap = {}
function mergeEnv (...envs: Array<Record<string, unknown>>) : Record<string, string> {

Check failure on line 10 in tabby-local/src/session.ts

View workflow job for this annotation

GitHub Actions / Lint

Unexpected space before the ':'

Check failure on line 10 in tabby-local/src/session.ts

View workflow job for this annotation

GitHub Actions / Lint

Array type using 'Array<T>' is forbidden. Use 'T[]' instead
const result: Record<string, string> = {}
const keyMap: Record<string, string> = {}
for (const env of envs) {
for (const [key, value] of Object.entries(env)) {
// const lookup = process.platform === 'win32' ? key.toLowerCase() : key
const lookup = key.toLowerCase()
keyMap[lookup] ??= key

Check failure on line 17 in tabby-local/src/session.ts

View workflow job for this annotation

GitHub Actions / Lint

Unnecessary conditional, expected left-hand side of `??` operator to be possibly null or undefined
result[keyMap[lookup]] = value
result[keyMap[lookup]] = value?.toString() ?? ''
}
}
return result
Expand Down Expand Up @@ -95,6 +95,15 @@
LC_MONETARY: locale,
})
}
if (this.hostApp.platform === Platform.macOS) {
if (!env.CLICOLOR || env.CLICOLOR === '0' || env.CLICOLOR.toLowerCase() === 'false') {
env.CLICOLOR = '1'
}
if (!env.CLICOLOR_FORCE || env.CLICOLOR_FORCE === '0' || env.CLICOLOR_FORCE.toLowerCase() === 'false') {
env.CLICOLOR_FORCE = '1'
}
env.LSCOLORS ??= 'exfxcxdxbxegedabagacad'

Check failure on line 105 in tabby-local/src/session.ts

View workflow job for this annotation

GitHub Actions / Lint

Unnecessary conditional, expected left-hand side of `??` operator to be possibly null or undefined
}

// eslint-disable-next-line @typescript-eslint/prefer-nullish-coalescing
let cwd = options.cwd || process.env.HOME
Expand Down
33 changes: 33 additions & 0 deletions tabby-ssh/src/api/fileSystem.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@

export interface FileEntry {
name: string
fullPath: string
isDirectory: boolean
isSymlink: boolean
mode: number
size: number
modified: Date
}

export interface FileHandle {
read (): Promise<Uint8Array>

Check failure on line 13 in tabby-ssh/src/api/fileSystem.ts

View workflow job for this annotation

GitHub Actions / Lint

Shorthand method signature is forbidden. Use a function property instead
write (chunk: Uint8Array): Promise<void>

Check failure on line 14 in tabby-ssh/src/api/fileSystem.ts

View workflow job for this annotation

GitHub Actions / Lint

Shorthand method signature is forbidden. Use a function property instead
close (): Promise<void>

Check failure on line 15 in tabby-ssh/src/api/fileSystem.ts

View workflow job for this annotation

GitHub Actions / Lint

Shorthand method signature is forbidden. Use a function property instead
}

export abstract class FileSystem {
abstract get pathSeparator (): string
abstract join (...paths: string[]): string
abstract dirname (p: string): string
abstract basename (p: string): string
abstract resolve (p: string): string

abstract readdir (p: string): Promise<FileEntry[]>
abstract stat (p: string): Promise<FileEntry>
abstract open (p: string, mode: number): Promise<FileHandle>
abstract mkdir (p: string): Promise<void>
abstract rmdir (p: string): Promise<void>
abstract unlink (p: string): Promise<void>
abstract rename (oldPath: string, newPath: string): Promise<void>
abstract chmod (p: string, mode: string|number): Promise<void>
}
Loading
Loading