Compare commits

...

6 Commits

23 changed files with 198 additions and 72 deletions
+1 -1
View File
@@ -1,7 +1,7 @@
name: "Build Helper"
on: workflow_dispatch
env:
WAVETERM_VERSION: 0.6.1
WAVETERM_VERSION: 0.6.3
GO_VERSION: "1.21.5"
NODE_VERSION: "21.5.0"
jobs:
+1 -1
View File
@@ -1,7 +1,7 @@
#!/bin/bash
# assumes we have Wave-darwin-x64-[version].zip and Wave-darwin-arm64-[version].zip in current directory
VERSION=0.6.1
VERSION=0.6.3
rm -rf temp
rm -rf builds
mkdir temp
+1
View File
@@ -1,3 +1,4 @@
github.com/aws/aws-sdk-go-v2/service/s3 v1.27.11 h1:3/gm/JTX9bX8CpzTgIlrtYpB3EVBDxyg/GY/QdcIEZw=
github.com/google/go-querystring v1.1.0 h1:AnCroh3fv4ZBgVIf1Iwtovgjaw/GiKJo8M8yD/fhyJ8=
github.com/kevinburke/ssh_config v1.2.0 h1:x584FjTGwHzMwvHx18PXxbBVzfnxogHaAReU4gf13a4=
github.com/kevinburke/ssh_config v1.2.0/go.mod h1:CT57kijsi8u/K/BOFA39wgDQJ9CxiF4nAY/ojJ6r6mM=
+1 -1
View File
@@ -2,7 +2,7 @@
"name": "waveterm",
"author": "Command Line Inc",
"productName": "Wave",
"version": "0.6.1",
"version": "0.6.3",
"main": "dist/emain.js",
"license": "Apache-2.0",
"dependencies": {
@@ -20,6 +20,12 @@
width: 100%;
}
.import-edit-warning {
display: flex;
flex-direction: row;
align-items: flex-start;
}
.name-actions-section {
margin-bottom: 10px;
display: flex;
+30 -3
View File
@@ -58,6 +58,10 @@ class EditRemoteConnModal extends React.Component<{}, {}> {
return this.selectedRemote?.local;
}
isImportedRemote(): boolean {
return this.selectedRemote?.sshconfigsrc == "sshconfig-import";
}
componentDidMount(): void {
mobx.action(() => {
this.tempAlias.set(this.selectedRemote?.remotealias);
@@ -259,6 +263,27 @@ class EditRemoteConnModal extends React.Component<{}, {}> {
);
}
renderImportedRemoteEditWarning() {
return (
<div className="import-edit-warning">
<Tooltip
message={
<span>
Most options for connections imported from an ssh config file cannot be edited. For these
changes, you must edit the config file and import it again. The shell preference can be
edited, but will return to the default if you import again. It will stay changed if you
follow <a href="https://docs.waveterm.dev/features/sshconfig-imports">this procedure</a>.
</span>
}
icon={<i className="fa-sharp fa-regular fa-fw fa-triangle-exclamation" />}
>
<i className="fa-sharp fa-regular fa-fw fa-triangle-exclamation" />
</Tooltip>
&nbsp;SSH Config Import Behavior
</div>
);
}
renderAuthMode() {
let authMode = this.tempAuthMode.get();
return (
@@ -344,6 +369,7 @@ class EditRemoteConnModal extends React.Component<{}, {}> {
return null;
}
let isLocal = this.isLocalRemote();
let isImported = this.isImportedRemote();
return (
<Modal className="erconn-modal">
<Modal.Header title="Edit Connection" onClose={this.model.closeModal} />
@@ -351,9 +377,10 @@ class EditRemoteConnModal extends React.Component<{}, {}> {
<div className="name-actions-section">
<div className="name text-primary">{util.getRemoteName(this.selectedRemote)}</div>
</div>
<If condition={!isLocal}>{this.renderAlias()}</If>
<If condition={!isLocal}>{this.renderAuthMode()}</If>
<If condition={!isLocal}>{this.renderConnectMode()}</If>
<If condition={!isLocal && !isImported}>{this.renderAlias()}</If>
<If condition={!isLocal && !isImported}>{this.renderAuthMode()}</If>
<If condition={!isLocal && !isImported}>{this.renderConnectMode()}</If>
<If condition={isImported}>{this.renderImportedRemoteEditWarning()}</If>
{this.renderShellPref()}
<If condition={!util.isBlank(this.remoteEdit?.errorstr)}>
<div className="settings-field settings-error">Error: {this.remoteEdit?.errorstr}</div>
+6 -12
View File
@@ -49,6 +49,7 @@ type OV<V> = mobx.IObservableValue<V>;
type OArr<V> = mobx.IObservableArray<V>;
const RemotePtyRows = 9;
const RemotePtyTotalRows = 25;
const RemotePtyCols = 80;
const NumOfLines = 50;
const PasswordUnchangedSentinel = "--unchanged--";
@@ -1026,17 +1027,6 @@ class ViewRemoteConnDetailModal extends React.Component<{}, {}> {
cancelInstallButton = <></>;
}
if (remote.sshconfigsrc == "sshconfig-import") {
updateAuthButton = (
<Button theme="secondary" disabled={true}>
Edit
<Tooltip
message={`Connections imported from an ssh config file cannot be edited inside waveterm. To edit these, you must edit the config file and import it again.`}
icon={<i className="fa-sharp fa-regular fa-fw fa-ban" />}
>
<i className="fa-sharp fa-regular fa-fw fa-ban" />
</Tooltip>
</Button>
);
archiveButton = (
<Button theme="secondary" onClick={() => this.clickArchive()}>
Delete
@@ -1195,7 +1185,11 @@ class ViewRemoteConnDetailModal extends React.Component<{}, {}> {
ref={this.termRef}
data-remoteid={remote.remoteid}
style={{
height: textmeasure.termHeightFromRows(RemotePtyRows, termFontSize),
height: textmeasure.termHeightFromRows(
RemotePtyRows,
termFontSize,
RemotePtyTotalRows
),
width: termWidth,
}}
></div>
+6 -12
View File
@@ -16,6 +16,7 @@ import * as textmeasure from "../../../util/textmeasure";
import "./viewremoteconndetail.less";
const RemotePtyRows = 9;
const RemotePtyTotalRows = 25;
const RemotePtyCols = 80;
@mobxReact.observer
@@ -209,17 +210,6 @@ class ViewRemoteConnDetailModal extends React.Component<{}, {}> {
cancelInstallButton = <></>;
}
if (remote.sshconfigsrc == "sshconfig-import") {
updateAuthButton = (
<Button theme="secondary" disabled={true}>
Edit
<Tooltip
message={`Connections imported from an ssh config file cannot be edited inside waveterm. To edit these, you must edit the config file and import it again.`}
icon={<i className="fa-sharp fa-regular fa-fw fa-ban" />}
>
<i className="fa-sharp fa-regular fa-fw fa-ban" />
</Tooltip>
</Button>
);
archiveButton = (
<Button theme="secondary" onClick={() => this.clickArchive()}>
Delete
@@ -382,7 +372,11 @@ class ViewRemoteConnDetailModal extends React.Component<{}, {}> {
ref={this.termRef}
data-remoteid={remote.remoteid}
style={{
height: textmeasure.termHeightFromRows(RemotePtyRows, termFontSize),
height: textmeasure.termHeightFromRows(
RemotePtyRows,
termFontSize,
RemotePtyTotalRows
),
width: termWidth,
}}
></div>
@@ -29,6 +29,7 @@ type OArr<V> = mobx.IObservableArray<V>;
type OMap<K, V> = mobx.ObservableMap<K, V>;
const RemotePtyRows = 8;
const RemotePtyTotalRows = 25;
const RemotePtyCols = 80;
const PasswordUnchangedSentinel = "--unchanged--";
@@ -1049,7 +1050,7 @@ class RemoteDetailView extends React.Component<{ model: RemotesModalModel; remot
ref={this.termRef}
data-remoteid={remote.remoteid}
style={{
height: textmeasure.termHeightFromRows(RemotePtyRows, termFontSize),
height: textmeasure.termHeightFromRows(RemotePtyRows, termFontSize, RemotePtyTotalRows),
width: termWidth,
}}
></div>
+1 -1
View File
@@ -399,7 +399,7 @@ class LineCmd extends React.Component<
let height = 45 + 24; // height of zero height terminal
const usedRows = screen.getUsedRows(lineutil.getRendererContext(line), line, cmd, width);
if (usedRows > 0) {
height = 48 + 24 + termHeightFromRows(usedRows, GlobalModel.termFontSize.get());
height = 48 + 24 + termHeightFromRows(usedRows, GlobalModel.termFontSize.get(), cmd.getTermMaxRows());
}
return height;
}
+5 -6
View File
@@ -84,11 +84,14 @@
}
.meta.meta-line1 {
margin-left: 2px;
color: rgba(@base-color, 0.6) !important;
font-size: 11px;
}
.meta.meta-line2 {
margin-left: -2px;
}
&.has-rtnstate .terminal-wrapper {
padding-bottom: 0;
}
@@ -113,11 +116,6 @@
overflow-x: hidden;
}
.terminal {
margin-right: 8px;
padding: 0.25rem;
}
&.cmd-done .terminal .xterm-cursor {
display: none;
}
@@ -466,6 +464,7 @@
padding: 0 0 10px 0;
flex-grow: 1;
position: relative;
overflow-x: hidden;
&::-webkit-scrollbar-thumb {
background-color: transparent !important;
-2
View File
@@ -18,8 +18,6 @@ let MagicLayout = {
ScreenMinContentSize: 100,
ScreenMaxContentSize: 5000,
// the 3 is for descenders, which get cut off in the terminal without this
TermDescendersHeight: 3,
TermWidthBuffer: 15,
TabWidth: 154,
+12 -2
View File
@@ -10,7 +10,16 @@ import { If, For } from "tsx-control-statements/components";
import cn from "classnames";
import { debounce } from "throttle-debounce";
import dayjs from "dayjs";
import { GlobalCommandRunner, TabColors, TabIcons, ForwardLineContainer, GlobalModel, ScreenLines, Screen, Session } from "../../../model/model";
import {
GlobalCommandRunner,
TabColors,
TabIcons,
ForwardLineContainer,
GlobalModel,
ScreenLines,
Screen,
Session,
} from "../../../model/model";
import type { LineType, RenderModeType, LineFactoryProps } from "../../../types/types";
import * as T from "../../../types/types";
import localizedFormat from "dayjs/plugin/localizedFormat";
@@ -114,6 +123,7 @@ class ScreenView extends React.Component<{ session: Session; screen: Screen }, {
return <div className="screen-view" ref={this.screenViewRef}></div>;
}
let fontSize = GlobalModel.termFontSize.get();
let dprStr = sprintf("%0.3f", GlobalModel.devicePixelRatio.get());
let viewOpts = screen.viewOpts.get();
let hasSidebar = viewOpts?.sidebar?.open;
let winWidth = "100%";
@@ -150,7 +160,7 @@ class ScreenView extends React.Component<{ session: Session; screen: Screen }, {
return (
<div className="screen-view" data-screenid={screen.screenId} ref={this.screenViewRef}>
<ScreenWindowView
key={screen.screenId + ":" + fontSize}
key={screen.screenId + ":" + fontSize + ":" + dprStr}
session={session}
screen={screen}
width={winWidth}
+39 -3
View File
@@ -170,6 +170,7 @@ function readAuthKey() {
return authKeyStr.trim();
}
let cmdOrAlt = process.platform === "darwin" ? "Cmd" : "Alt";
let menuTemplate = [
{
role: "appMenu",
@@ -198,9 +199,41 @@ let menuTemplate = [
{ role: "reload", accelerator: "Option+R" },
{ role: "toggleDevTools" },
{ type: "separator" },
{ role: "resetZoom" },
{ role: "zoomIn" },
{ role: "zoomOut" },
{
label: "Actual Size",
accelerator: cmdOrAlt + "+0",
click: () => {
if (MainWindow == null) {
return;
}
MainWindow.webContents.setZoomFactor(1);
MainWindow.webContents.send("zoom-changed");
},
},
{
label: "Zoom In",
accelerator: cmdOrAlt + "+Plus",
click: () => {
if (MainWindow == null) {
return;
}
const zoomFactor = MainWindow.webContents.getZoomFactor();
MainWindow.webContents.setZoomFactor(zoomFactor * 1.1);
MainWindow.webContents.send("zoom-changed");
},
},
{
label: "Zoom Out",
accelerator: cmdOrAlt + "+-",
click: () => {
if (MainWindow == null) {
return;
}
const zoomFactor = MainWindow.webContents.getZoomFactor();
MainWindow.webContents.setZoomFactor(zoomFactor / 1.1);
MainWindow.webContents.send("zoom-changed");
},
},
{ type: "separator" },
{ role: "togglefullscreen" },
],
@@ -367,6 +400,9 @@ function createMainWindow(clientData) {
win.on("close", () => {
MainWindow = null;
});
win.webContents.on("zoom-changed", (e) => {
win.webContents.send("zoom-changed");
});
win.webContents.setWindowOpenHandler(({ url, frameName }) => {
if (url.startsWith("https://docs.waveterm.dev/")) {
console.log("openExternal docs", url);
+1
View File
@@ -20,6 +20,7 @@ contextBridge.exposeInMainWorld("api", {
onWCmd: (callback) => ipcRenderer.on("w-cmd", callback),
onPCmd: (callback) => ipcRenderer.on("p-cmd", callback),
onRCmd: (callback) => ipcRenderer.on("r-cmd", callback),
onZoomChanged: (callback) => ipcRenderer.on("zoom-changed", callback),
onMetaArrowUp: (callback) => ipcRenderer.on("meta-arrowup", callback),
onMetaArrowDown: (callback) => ipcRenderer.on("meta-arrowdown", callback),
onMetaPageUp: (callback) => ipcRenderer.on("meta-pageup", callback),
+4 -7
View File
@@ -8,6 +8,7 @@ import { sprintf } from "sprintf-js";
import { App } from "./app/app";
import * as DOMPurify from "dompurify";
import { loadFonts } from "./util/util";
import * as textmeasure from "./util/textmeasure";
// @ts-ignore
let VERSION = __WAVETERM_VERSION__;
@@ -20,18 +21,14 @@ document.addEventListener("DOMContentLoaded", () => {
let reactElem = React.createElement(App, null, null);
let elem = document.getElementById("app");
let root = createRoot(elem);
let isFontLoaded = document.fonts.check("12px 'JetBrains Mono'");
if (isFontLoaded) {
document.fonts.ready.then(() => {
root.render(reactElem);
} else {
document.fonts.ready.then(() => {
root.render(reactElem);
});
}
});
});
(window as any).mobx = mobx;
(window as any).sprintf = sprintf;
(window as any).DOMPurify = DOMPurify;
(window as any).textmeasure = textmeasure;
console.log("WaveTerm", VERSION, BUILD);
+37 -3
View File
@@ -74,6 +74,7 @@ import {
windowHeightToRows,
termWidthFromCols,
termHeightFromRows,
clearMonoFontCache,
} from "../util/textmeasure";
import dayjs from "dayjs";
import localizedFormat from "dayjs/plugin/localizedFormat";
@@ -203,6 +204,7 @@ type ElectronApi = {
onPCmd: (callback: (mods: KeyModsType) => void) => void;
onRCmd: (callback: (mods: KeyModsType) => void) => void;
onWCmd: (callback: (mods: KeyModsType) => void) => void;
onZoomChanged: (callback: () => void) => void;
onMenuItemAbout: (callback: () => void) => void;
onMetaArrowUp: (callback: () => void) => void;
onMetaArrowDown: (callback: () => void) => void;
@@ -306,6 +308,11 @@ class Cmd {
return this.data.get().termopts;
}
getTermMaxRows(): number {
let termOpts = this.getTermOpts();
return termOpts?.rows;
}
getCmdStr(): string {
return this.data.get().cmdstr;
}
@@ -741,7 +748,7 @@ class Screen {
getMaxContentSize(): WindowSize {
if (this.lastScreenSize == null) {
let width = termWidthFromCols(80, GlobalModel.termFontSize.get());
let height = termHeightFromRows(25, GlobalModel.termFontSize.get());
let height = termHeightFromRows(25, GlobalModel.termFontSize.get(), 25);
return { width, height };
}
let winSize = this.lastScreenSize;
@@ -755,7 +762,7 @@ class Screen {
getIdealContentSize(): WindowSize {
if (this.lastScreenSize == null) {
let width = termWidthFromCols(80, GlobalModel.termFontSize.get());
let height = termHeightFromRows(25, GlobalModel.termFontSize.get());
let height = termHeightFromRows(25, GlobalModel.termFontSize.get(), 25);
return { width, height };
}
let winSize = this.lastScreenSize;
@@ -2394,7 +2401,7 @@ class HistoryViewModel {
} else {
this.activeItem.set(hitem.historyid);
let width = termWidthFromCols(80, GlobalModel.termFontSize.get());
let height = termHeightFromRows(25, GlobalModel.termFontSize.get());
let height = termHeightFromRows(25, GlobalModel.termFontSize.get(), 25);
this.specialLineContainer = new SpecialLineContainer(
this,
{ width, height },
@@ -3449,6 +3456,9 @@ class Model {
lineSettingsModal: OV<number> = mobx.observable.box(null, {
name: "lineSettingsModal",
}); // linenum
devicePixelRatio: OV<number> = mobx.observable.box(window.devicePixelRatio, {
name: "devicePixelRatio",
});
remotesModalModel: RemotesModalModel;
remotesModel: RemotesModel;
@@ -3513,6 +3523,7 @@ class Model {
getApi().onPCmd(this.onPCmd.bind(this));
getApi().onWCmd(this.onWCmd.bind(this));
getApi().onRCmd(this.onRCmd.bind(this));
getApi().onZoomChanged(this.onZoomChanged.bind(this));
getApi().onMenuItemAbout(this.onMenuItemAbout.bind(this));
getApi().onMetaArrowUp(this.onMetaArrowUp.bind(this));
getApi().onMetaArrowDown(this.onMetaArrowDown.bind(this));
@@ -3824,6 +3835,29 @@ class Model {
}
}
onZoomChanged(): void {
mobx.action(() => {
this.devicePixelRatio.set(window.devicePixelRatio);
clearMonoFontCache();
})();
}
getSelectedTermWrap(): TermWrap {
let screen = this.getActiveScreen();
if (screen == null) {
return null;
}
let lineNum = screen.selectedLine.get();
if (lineNum == null) {
return null;
}
let line = screen.getLineByNum(lineNum);
if (line == null) {
return null;
}
return screen.getTermWrap(line.lineid);
}
clearModals(): boolean {
let didSomething = false;
mobx.action(() => {
+2 -1
View File
@@ -153,7 +153,7 @@ class TerminalRenderer extends React.Component<
.get();
let cmd = screen.getCmd(line); // will not be null
let usedRows = screen.getUsedRows(lineutil.getRendererContext(line), line, cmd, width);
let termHeight = termHeightFromRows(usedRows, GlobalModel.termFontSize.get());
let termHeight = termHeightFromRows(usedRows, GlobalModel.termFontSize.get(), cmd.getTermMaxRows());
if (usedRows === 0) {
termHeight = 0;
}
@@ -169,6 +169,7 @@ class TerminalRenderer extends React.Component<
{ "zero-height": termHeight == 0 },
{ collapsed: collapsed }
)}
data-usedrows={usedRows}
>
<If condition={!isFocused}>
<div key="term-block" className="term-block" onClick={this.clickTermBlock}></div>
+28 -6
View File
@@ -30,6 +30,10 @@ function getMonoFontSize(fontSize: number): { height: number; width: number } {
return size;
}
function clearMonoFontCache(): void {
MonoFontSizes = [];
}
function measureText(
text: string,
textOpts?: { pre?: boolean; mono?: boolean; fontSize?: number | string }
@@ -57,8 +61,9 @@ function measureText(
throw new Error("cannot measure text, no #measure div");
}
measureDiv.replaceChildren(textElem);
let rect = textElem.getBoundingClientRect();
return { width: rect.width, height: Math.ceil(rect.height) };
let height = textElem.offsetHeight;
let width = textElem.offsetWidth;
return { width: width, height: Math.ceil(height) };
}
function windowWidthToCols(width: number, fontSize: number): number {
@@ -82,10 +87,27 @@ function termWidthFromCols(cols: number, fontSize: number): number {
return Math.ceil(dr.width * cols) + MagicLayout.TermWidthBuffer;
}
function termHeightFromRows(rows: number, fontSize: number): number {
// we need to match the xtermjs calculation in CharSizeService.ts and DomRenderer.ts
// it does some crazy rounding depending on the value of window.devicePixelRatio
// works out to `realHeight = round(ceil(height * dpr) * rows / dpr) / rows`
// their calculation is based off the "totalRows" (so that argument has been added)
function termHeightFromRows(rows: number, fontSize: number, totalRows: number): number {
let dr = getMonoFontSize(fontSize);
// TODO: replace the TermDescendersHeight with some calculation based on termFontSize.
return Math.ceil(dr.height * rows) + MagicLayout.TermDescendersHeight;
const dpr = window.devicePixelRatio;
if (totalRows == null || totalRows == 0) {
totalRows = rows > 25 ? rows : 25;
}
let realHeight = Math.round((Math.ceil(dr.height * dpr) * totalRows) / dpr) / totalRows;
return Math.ceil(realHeight * rows);
}
export { measureText, getMonoFontSize, windowWidthToCols, windowHeightToRows, termWidthFromCols, termHeightFromRows };
export {
measureText,
getMonoFontSize,
windowWidthToCols,
windowHeightToRows,
termWidthFromCols,
termHeightFromRows,
clearMonoFontCache,
MonoFontSizes,
};
+1 -1
View File
@@ -1,2 +1,2 @@
const VERSION = "v0.6.1";
const VERSION = "v0.6.3";
module.exports = VERSION;

Some files were not shown because too many files have changed in this diff Show More