Documentation
¶
Overview ¶
Package iterm2 is a Go client for the iTerm2 API.
iTerm2 exposes the same API its Python scripting library uses: a WebSocket carrying protocol-buffer messages over a unix domain socket in the application's support directory. This package speaks that protocol directly, so nothing here needs Python, iTerm2's bundled runtime, or a script installed into iTerm2's scripts folder.
Enabling the API ¶
iTerm2 rejects every connection until the API is switched on in Settings > General > Magic > Enable Python API. The name says Python; the setting governs the socket, not the language.
Connecting ¶
conn, err := iterm2.Connect(ctx)
if err != nil {
return err
}
defer conn.Close()
h, err := conn.ListSessions(ctx)
if err != nil {
return err
}
for _, s := range h.Sessions() {
fmt.Println(s.ID, s.Title)
}
Connect authorises the connection with a single-use cookie. It reads ITERM2_COOKIE and ITERM2_KEY if they are set — which they are for a process iTerm2 launched itself — and otherwise asks the running iTerm2 for a fresh pair over AppleScript, which requires macOS. Pass WithCredentials to supply them yourself.
Two layers ¶
The hand-written surface — Conn, Hierarchy, Window, Tab, Session and their methods — is the stable one, and covers the session hierarchy, sending text, creating tabs and splits, closing things, variables and notifications.
Everything else iTerm2 can do is reachable through Conn.Do, which sends one ClientOriginatedMessage from the apipb package and returns its response. That includes profiles, the screen contents, transactions, registering a toolbelt tool and the rest of api.proto. apipb is generated from iTerm2's api.proto and tracks it: UPSTREAM.md records the commit it came from, what is verified, and what is not.
Concurrency ¶
A Conn is safe for concurrent use. Requests from many goroutines are serialised onto the socket and matched to their responses by message id, so one slow request does not block another.
Notifications are delivered to a Subscription's channel and are dropped rather than blocking when the consumer falls behind, because the read loop delivers them and a blocked reader would stall every request on the connection. Subscription.Dropped counts what was lost.
Index ¶
- Constants
- Variables
- func DefaultSocketPath() string
- type APIError
- type ActivateOptions
- type Client
- type Conn
- func (c *Conn) Activate(ctx context.Context, opts ActivateOptions) error
- func (c *Conn) Close() error
- func (c *Conn) CloseSessions(ctx context.Context, force bool, ids ...string) error
- func (c *Conn) CloseTabs(ctx context.Context, force bool, ids ...string) error
- func (c *Conn) CloseWindows(ctx context.Context, force bool, ids ...string) error
- func (c *Conn) CreateTab(ctx context.Context, opts CreateTabOptions) (*NewTab, error)
- func (c *Conn) Do(ctx context.Context, req *apipb.ClientOriginatedMessage) (*apipb.ServerOriginatedMessage, error)
- func (c *Conn) Done() <-chan struct{}
- func (c *Conn) Err() error
- func (c *Conn) GetStringVariable(ctx context.Context, scope VariableScope, identifier, name string) (value string, ok bool, err error)
- func (c *Conn) GetVariables(ctx context.Context, scope VariableScope, identifier string, names ...string) (map[string]json.RawMessage, error)
- func (c *Conn) ListSessions(ctx context.Context) (*Hierarchy, error)
- func (c *Conn) RegisterContextMenuItem(ctx context.Context, m ContextMenuItem) (*RPCRegistration, error)
- func (c *Conn) RegisterRPC(ctx context.Context, fn RPC) (*RPCRegistration, error)
- func (c *Conn) RegisterTitleProvider(ctx context.Context, t TitleProvider) (*RPCRegistration, error)
- func (c *Conn) RegisterTool(ctx context.Context, t Tool) error
- func (c *Conn) SendText(ctx context.Context, sessionID, text string, suppressBroadcast bool) error
- func (c *Conn) SetStringVariable(ctx context.Context, scope VariableScope, identifier, name, value string) error
- func (c *Conn) SetVariables(ctx context.Context, scope VariableScope, identifier string, ...) error
- func (c *Conn) SplitPane(ctx context.Context, sessionID string, opts SplitPaneOptions) ([]string, error)
- func (c *Conn) Subscribe(ctx context.Context, req *apipb.NotificationRequest) (*Subscription, error)
- func (c *Conn) SubscribeFocusChanges(ctx context.Context) (*Subscription, error)
- func (c *Conn) SubscribeLayoutChanges(ctx context.Context) (*Subscription, error)
- func (c *Conn) SubscribeNewSessions(ctx context.Context) (*Subscription, error)
- func (c *Conn) SubscribeTerminatedSessions(ctx context.Context) (*Subscription, error)
- func (c *Conn) SubscribeVariableChanges(ctx context.Context, scope VariableScope, identifier, name string) (*Subscription, error)
- type ContextMenuItem
- type CreateTabOptions
- type CredentialSource
- type CredentialSourceFunc
- type Credentials
- type DurableSubscription
- type Hierarchy
- type NewTab
- type Option
- func ForceTCP() Option
- func WithAdvisoryName(name string) Option
- func WithCredentialSource(src CredentialSource) Option
- func WithCredentials(cookie, key string) Option
- func WithReconnectBackoff(min, max time.Duration) Option
- func WithSocketPath(path string) Option
- func WithSubscriptionBuffer(n int) Option
- func WithTCPAddress(addr string) Option
- type Persistent
- func (p *Persistent) Activate(ctx context.Context, opts ActivateOptions) error
- func (p *Persistent) Close() error
- func (p *Persistent) CloseSessions(ctx context.Context, force bool, ids ...string) error
- func (p *Persistent) CloseTabs(ctx context.Context, force bool, ids ...string) error
- func (p *Persistent) CloseWindows(ctx context.Context, force bool, ids ...string) error
- func (p *Persistent) Conn() (*Conn, error)
- func (p *Persistent) CreateTab(ctx context.Context, opts CreateTabOptions) (*NewTab, error)
- func (p *Persistent) Do(ctx context.Context, req *apipb.ClientOriginatedMessage) (*apipb.ServerOriginatedMessage, error)
- func (p *Persistent) GetStringVariable(ctx context.Context, scope VariableScope, identifier, name string) (value string, ok bool, err error)
- func (p *Persistent) GetVariables(ctx context.Context, scope VariableScope, identifier string, names ...string) (map[string]json.RawMessage, error)
- func (p *Persistent) ListSessions(ctx context.Context) (*Hierarchy, error)
- func (p *Persistent) Reconnects() <-chan Reconnect
- func (p *Persistent) RegisterContextMenuItem(ctx context.Context, m ContextMenuItem) (*RPCRegistration, error)
- func (p *Persistent) RegisterRPC(ctx context.Context, fn RPC) (*RPCRegistration, error)
- func (p *Persistent) RegisterTitleProvider(ctx context.Context, t TitleProvider) (*RPCRegistration, error)
- func (p *Persistent) RegisterTool(ctx context.Context, t Tool) error
- func (p *Persistent) SendText(ctx context.Context, sessionID, text string, suppressBroadcast bool) error
- func (p *Persistent) SetStringVariable(ctx context.Context, scope VariableScope, identifier, name, value string) error
- func (p *Persistent) SetVariables(ctx context.Context, scope VariableScope, identifier string, ...) error
- func (p *Persistent) SplitPane(ctx context.Context, sessionID string, opts SplitPaneOptions) ([]string, error)
- func (p *Persistent) Subscribe(ctx context.Context, req *apipb.NotificationRequest) (*DurableSubscription, error)
- func (p *Persistent) SubscribeFocusChanges(ctx context.Context) (*DurableSubscription, error)
- func (p *Persistent) SubscribeLayoutChanges(ctx context.Context) (*DurableSubscription, error)
- func (p *Persistent) SubscribeNewSessions(ctx context.Context) (*DurableSubscription, error)
- func (p *Persistent) SubscribeTerminatedSessions(ctx context.Context) (*DurableSubscription, error)
- func (p *Persistent) SubscribeVariableChanges(ctx context.Context, scope VariableScope, identifier, name string) (*DurableSubscription, error)
- type RPC
- type RPCRegistration
- type Reconnect
- type Rect
- type Session
- func (s *Session) Activate(ctx context.Context, opts ActivateOptions) error
- func (s *Session) Close(ctx context.Context, force bool) error
- func (s *Session) SendText(ctx context.Context, text string) error
- func (s *Session) SetVariable(ctx context.Context, name, value string) error
- func (s *Session) SplitPane(ctx context.Context, opts SplitPaneOptions) ([]string, error)
- func (s *Session) Variable(ctx context.Context, name string) (string, bool, error)
- type Size
- type SplitDirection
- type SplitNode
- type SplitPaneOptions
- type StatusError
- type Subscription
- type Tab
- type TabGroup
- type TitleProvider
- type Tool
- type VariableScope
- type Window
Constants ¶
const ( // Subprotocol is the WebSocket subprotocol iTerm2 requires. iTerm2 refuses // the upgrade unless sec-websocket-protocol matches it exactly // (iTermWebSocketConnection.m, kProtocolName). Subprotocol = "api.iterm2.com" // LibraryVersion is reported in the x-iterm2-library-version header as // "go <LibraryVersion>". // // iTerm2 requires the header to be two space-separated fields and compares // the second against a per-language minimum. It publishes a minimum for // "python" only, so "go" is not version-gated today — iTerm2's own Swift // client sends "swift 1.0" on the same basis. The value is a plain decimal // rather than this module's semantic version because that is what the // comparison parses; it is not a promise about anything else, and it moves // only if iTerm2 starts gating Go clients. LibraryVersion = "0.1" // LegacyTCPAddress is the loopback address iTerm2 listened on before the // unix domain socket, and still accepts. [Connect] falls back to it when the // socket is absent, which is what iTerm2's Python library does. LegacyTCPAddress = "localhost:1912" )
const ( // SessionAll addresses every session at once. SessionAll = "all" // SessionActive addresses whichever session currently has keyboard focus. SessionActive = "active" )
Session identifiers that iTerm2 accepts in place of a real one, documented at the top of api.proto. Not every request accepts them; the comment on each request message in api.proto says which do.
const AllVariables = "*"
AllVariables is the name that asks for every variable in one JSON object instead of a single value, as api.proto's "special value" for the get field.
Variables ¶
var ErrClosed = errors.New("iterm2: connection closed")
ErrClosed is returned by every operation on a Conn whose connection has gone away, whether because Conn.Close was called or because iTerm2 quit.
var ErrNoCredentials = errors.New("iterm2: ITERM2_COOKIE and ITERM2_KEY are not set")
ErrNoCredentials is returned by EnvCredentials when neither ITERM2_COOKIE nor ITERM2_KEY is set.
var ErrNotSupported = errors.New("iterm2: not supported by this iTerm2")
ErrNotSupported reports a request iTerm2 understood but declined as unavailable, such as a notification type this iTerm2 version does not post.
var ErrReconnecting = fmt.Errorf("iterm2: reconnecting to iTerm2: %w", ErrClosed)
ErrReconnecting is returned by a Persistent connection while it has lost iTerm2 and is dialling again. It wraps ErrClosed, so code that already checks for a closed connection keeps working.
ErrUnauthorized wraps a handshake iTerm2 refused. The usual causes are the Python API being switched off in Settings > General > Magic, and a cookie that has already been used — iTerm2 consumes each one exactly once.
Functions ¶
func DefaultSocketPath ¶
func DefaultSocketPath() string
DefaultSocketPath returns the unix domain socket a running iTerm2 listens on.
It honours IT2_SUITE, which iTerm2 uses to keep parallel builds — a nightly alongside a release — from sharing one support directory.
Types ¶
type APIError ¶
type APIError struct {
Message string
}
APIError is iTerm2's report that a request could not be understood. It corresponds to the `error` field of ServerOriginatedMessage, which iTerm2 sets only for a malformed request — never as an ordinary outcome.
type ActivateOptions ¶
type ActivateOptions struct {
// OrderWindowFront raises the window containing the target.
OrderWindowFront bool
// SelectTab selects the target's tab. Valid for a tab or a session.
SelectTab bool
// SelectSession selects the target pane within its tab. Valid for a session.
SelectSession bool
// ActivateApp brings iTerm2 itself to the front.
ActivateApp bool
// RaiseAllWindows and IgnoringOtherApps apply only with ActivateApp, and
// correspond to ActivateRequest.App in api.proto.
RaiseAllWindows bool
IgnoringOtherApps bool
}
ActivateOptions asks for more than the default of bringing one object forward.
type Client ¶ added in v0.4.0
type Client interface {
Do(ctx context.Context, req *apipb.ClientOriginatedMessage) (*apipb.ServerOriginatedMessage, error)
ListSessions(ctx context.Context) (*Hierarchy, error)
CreateTab(ctx context.Context, opts CreateTabOptions) (*NewTab, error)
SendText(ctx context.Context, sessionID, text string, suppressBroadcast bool) error
SplitPane(ctx context.Context, sessionID string, opts SplitPaneOptions) ([]string, error)
Activate(ctx context.Context, opts ActivateOptions) error
CloseSessions(ctx context.Context, force bool, ids ...string) error
CloseTabs(ctx context.Context, force bool, ids ...string) error
CloseWindows(ctx context.Context, force bool, ids ...string) error
GetVariables(ctx context.Context, scope VariableScope, identifier string, names ...string) (map[string]json.RawMessage, error)
GetStringVariable(ctx context.Context, scope VariableScope, identifier, name string) (value string, ok bool, err error)
SetVariables(ctx context.Context, scope VariableScope, identifier string, values map[string]string) error
SetStringVariable(ctx context.Context, scope VariableScope, identifier, name, value string) error
}
Client is the request surface *Conn and *Persistent share, so code can be written once and handed either. Subscriptions are not part of it: a Persistent's outlive a reconnect and are a different type.
type Conn ¶
type Conn struct {
// contains filtered or unexported fields
}
Conn is a connection to a running iTerm2.
A Conn is safe for concurrent use: requests from many goroutines are serialised onto the socket and matched to their responses by message id.
Every method takes a context. Cancelling one abandons that request only — a response arriving afterwards is discarded. To tear the connection down, call Conn.Close.
func Connect ¶
Connect dials a running iTerm2 and completes the API handshake.
It prefers the unix domain socket at DefaultSocketPath and falls back to LegacyTCPAddress when that socket does not exist, matching iTerm2's own Python library.
The API must be enabled in iTerm2 (Settings > General > Magic > Enable Python API) or the handshake fails with an error wrapping ErrUnauthorized.
func (*Conn) Activate ¶
func (c *Conn) Activate(ctx context.Context, opts ActivateOptions) error
Activate brings iTerm2 to the front without selecting anything in particular.
func (*Conn) Close ¶
Close shuts the connection down and waits for its reader to finish.
Requests in flight fail with ErrClosed, and every Subscription channel is closed. Calling it more than once is harmless, and calling it on a connection iTerm2 already dropped returns nil.
func (*Conn) CloseSessions ¶
CloseSessions closes panes by id.
force skips the confirmation iTerm2 would otherwise show for a session with a running job; without it, a user who declines leaves that session open and the call reports USER_DECLINED for it.
iTerm2 answers with one status per target, so closing several can partly succeed. The returned error joins one *StatusError per target that failed, naming it, and is nil only when every one closed.
func (*Conn) CloseTabs ¶
CloseTabs closes tabs by id. See Conn.CloseSessions for force and the per-target statuses.
func (*Conn) CloseWindows ¶
CloseWindows closes windows by id. See Conn.CloseSessions for force and the per-target statuses.
func (*Conn) Do ¶
func (c *Conn) Do(ctx context.Context, req *apipb.ClientOriginatedMessage) (*apipb.ServerOriginatedMessage, error)
Do sends one request and returns iTerm2's response to it.
This is the whole API: every request type in api.proto is a field of apipb.ClientOriginatedMessage, and the typed methods on Conn are built on this one. req is not modified — Do sends a copy carrying the message id.
A response whose `error` field is set comes back as an *APIError, because iTerm2 sets it only for a request it could not parse. Per-request status enums are left in the response for the caller to read; the typed methods turn a non-OK status into a *StatusError.
func (*Conn) Done ¶ added in v0.2.0
func (c *Conn) Done() <-chan struct{}
Done is closed when the connection ends, whether through Conn.Close or because iTerm2 went away. Conn.Err then says which.
A program that only listens has no request in flight to fail, so without this it cannot tell iTerm2 has quit. A connection cannot be revived — its cookie is spent — so the response to Done is a fresh Connect:
for {
conn, err := iterm2.Connect(ctx)
if err != nil { /* back off and retry */ }
// subscribe to what you need; notifications posted while
// disconnected are gone, so resynchronise any state here
<-conn.Done()
}
func (*Conn) Err ¶ added in v0.2.0
Err is nil while the connection is up. Once Conn.Done is closed it reports why: ErrClosed after Conn.Close, or the error that ended the connection when iTerm2 dropped it.
func (*Conn) GetStringVariable ¶
func (c *Conn) GetStringVariable(ctx context.Context, scope VariableScope, identifier, name string) (value string, ok bool, err error)
GetStringVariable reads one variable and decodes it as a string.
It returns ok false when the variable is unset. A variable holding something other than a string — a number, or the object AllVariables returns — is an error, because silently rendering it would hide the mismatch.
func (*Conn) GetVariables ¶
func (c *Conn) GetVariables(ctx context.Context, scope VariableScope, identifier string, names ...string) (map[string]json.RawMessage, error)
GetVariables reads variables from one object.
identifier names the session, tab or window, and is ignored for ScopeApp. The returned values are JSON, exactly as iTerm2 sends them: a string variable arrives quoted. Use Conn.GetStringVariable when a string is what is wanted.
The result is keyed by the requested name and omits any variable iTerm2 reported as unset, which it does by sending JSON null.
iTerm2 refuses to read more than one variable at once from SessionAll and answers MULTI_GET_DISALLOWED.
func (*Conn) ListSessions ¶
ListSessions returns a snapshot of every window, tab and session.
func (*Conn) RegisterContextMenuItem ¶ added in v0.9.0
func (c *Conn) RegisterContextMenuItem(ctx context.Context, m ContextMenuItem) (*RPCRegistration, error)
RegisterContextMenuItem adds m to iTerm2's session context menu and answers its calls until it is unregistered or the connection ends.
func (*Conn) RegisterRPC ¶ added in v0.7.0
RegisterRPC registers fn and answers iTerm2's calls to it until it is unregistered or the connection ends.
func (*Conn) RegisterTitleProvider ¶ added in v0.8.0
func (c *Conn) RegisterTitleProvider(ctx context.Context, t TitleProvider) (*RPCRegistration, error)
RegisterTitleProvider registers t in iTerm2's session-title role and answers its calls until it is unregistered or the connection ends.
func (*Conn) RegisterTool ¶ added in v0.6.0
RegisterTool adds a web-view panel to iTerm2's toolbelt.
iTerm2 forgets the tool when it quits. Persistent.RegisterTool registers it again on every new connection.
func (*Conn) SendText ¶
SendText types text into the session, as though the user had.
The session may be SessionAll or SessionActive. suppressBroadcast keeps the text out of other sessions when the user has broadcasting switched on.
func (*Conn) SetStringVariable ¶
func (c *Conn) SetStringVariable(ctx context.Context, scope VariableScope, identifier, name, value string) error
SetStringVariable writes one string variable, doing the JSON quoting.
The name must begin with "user." — see Conn.SetVariables.
func (*Conn) SetVariables ¶
func (c *Conn) SetVariables(ctx context.Context, scope VariableScope, identifier string, values map[string]string) error
SetVariables writes variables on one object.
Values must be JSON, so a string needs its quotes. iTerm2 rejects any name not beginning with "user." and answers INVALID_NAME, which arrives as a *StatusError: the built-in variables are iTerm2's to write, not a script's.
func (*Conn) SplitPane ¶
func (c *Conn) SplitPane(ctx context.Context, sessionID string, opts SplitPaneOptions) ([]string, error)
SplitPane divides a session and returns the ids of the sessions created.
More than one id comes back when sessionID is SessionAll. api.proto warns that a tmux integration session reports none, because the split happens only if and when the tmux server acts on it.
func (*Conn) Subscribe ¶
func (c *Conn) Subscribe(ctx context.Context, req *apipb.NotificationRequest) (*Subscription, error)
Subscribe asks iTerm2 to post notifications and returns them on a channel.
req must set NotificationType. Everything else api.proto allows — the session to watch, a VariableMonitorRequest, a KeystrokePattern filter — is passed through untouched, so this covers notification types this package has no named helper for. Subscribe sets Subscribe itself.
The returned Subscription must be released with Subscription.Unsubscribe, or iTerm2 keeps posting for the life of the connection.
func (*Conn) SubscribeFocusChanges ¶
func (c *Conn) SubscribeFocusChanges(ctx context.Context) (*Subscription, error)
SubscribeFocusChanges posts a notification when the application, window, tab or pane with focus changes. api.proto warns that duplicates are normal; ignore the ones that report no change.
func (*Conn) SubscribeLayoutChanges ¶
func (c *Conn) SubscribeLayoutChanges(ctx context.Context) (*Subscription, error)
SubscribeLayoutChanges posts a notification whenever windows, tabs or panes move. Each carries a full hierarchy snapshot, the same shape Conn.ListSessions returns.
func (*Conn) SubscribeNewSessions ¶
func (c *Conn) SubscribeNewSessions(ctx context.Context) (*Subscription, error)
SubscribeNewSessions posts a notification whenever a session is created, or a closed one is restored by undo. Read the id from apipb.Notification.GetNewSessionNotification.
func (*Conn) SubscribeTerminatedSessions ¶
func (c *Conn) SubscribeTerminatedSessions(ctx context.Context) (*Subscription, error)
SubscribeTerminatedSessions posts a notification whenever a session ends.
func (*Conn) SubscribeVariableChanges ¶
func (c *Conn) SubscribeVariableChanges(ctx context.Context, scope VariableScope, identifier, name string) (*Subscription, error)
SubscribeVariableChanges posts a notification when a variable changes.
identifier names the session, tab or window to watch and is ignored for ScopeApp. name is the variable, such as "jobName" or "user.myVariable".
type ContextMenuItem ¶ added in v0.9.0
type ContextMenuItem struct {
RPC
// DisplayName is the menu item's label.
DisplayName string
// Identifier must be unique among context-menu items; api.proto asks for a
// reverse-DNS name, such as com.example.copy-path.
Identifier string
}
ContextMenuItem is an RPC offered as an item in a session's context menu, labelled DisplayName. Choosing it calls the Handler; map arguments to session variables in Defaults, such as "session.path", to act on the session the menu was opened on. iTerm2 does not show the result.
type CreateTabOptions ¶
type CreateTabOptions struct {
// ProfileName selects the profile. Empty uses the default profile.
ProfileName string
// WindowID puts the tab in an existing window. Empty creates a new window.
WindowID string
// TabIndex is the position for the new tab, and is valid only with WindowID.
// nil lets iTerm2 choose. An index iTerm2 cannot honour still creates the
// tab — it answers INVALID_TAB_INDEX, which arrives as a [*StatusError]
// even though the tab now exists.
TabIndex *uint32
// SelectTab, when pointed at false, creates the tab in the background
// without selecting it or raising its window. nil keeps iTerm2's default of
// selecting it.
SelectTab *bool
// CustomProfileProperties overrides profile settings for this session only.
// Each value must be JSON, matching ProfileProperty.json_value in
// api.proto — a string setting therefore needs its quotes, as in
// `{"Command": "\"/bin/zsh\""}`.
CustomProfileProperties map[string]string
}
CreateTabOptions configures Conn.CreateTab.
It is a struct rather than a list of functional options so that a field added later is an additive change for callers who construct it with field names.
type CredentialSource ¶
type CredentialSource interface {
Credentials(ctx context.Context) (Credentials, error)
}
CredentialSource supplies credentials for one connection attempt.
It is called once per attempt rather than once per Conn, because a cookie is consumed by the attempt whether or not the attempt succeeds.
func AppleScriptCredentials ¶
func AppleScriptCredentials(advisoryName string) CredentialSource
AppleScriptCredentials asks a running iTerm2 for a fresh single-use cookie.
advisoryName is shown to the user in iTerm2's script console and in the permission prompt, so it should name the program rather than the library.
This requires macOS and a running iTerm2: it drives /usr/bin/osascript, and on any other platform it fails without running anything. The user may be asked to approve the connection the first time a given key appears.
IT2_APP_PATH, if set, selects which iTerm2 build to ask — matching the behaviour of iTerm2's own it2 CLI, and needed only when several are running.
func DefaultCredentials ¶
func DefaultCredentials(advisoryName string) CredentialSource
DefaultCredentials uses the environment when iTerm2 has provided credentials there, and otherwise asks iTerm2 for a fresh cookie over AppleScript.
The environment's cookie is used once per process. iTerm2 issues it single use and forgets every cookie when it restarts, so presenting it a second time can only be refused; after the first attempt this source asks over AppleScript instead, which is what lets a program reconnect. And when the environment's cookie is refused outright — inherited from a parent that already spent it — Connect asks for a fresh one and tries once more. Both match iTerm2's Python library, which deletes ITERM2_COOKIE after a refusal; this one leaves the environment alone and remembers the spent value instead.
func EnvCredentials ¶
func EnvCredentials() CredentialSource
EnvCredentials reads ITERM2_COOKIE and ITERM2_KEY from the environment.
iTerm2 sets both for processes it launches itself, including scripts run from its Scripts menu. It returns ErrNoCredentials when neither is set, so it can be chained ahead of AppleScriptCredentials — which is what DefaultCredentials does.
func StaticCredentials ¶
func StaticCredentials(cookie, key string) CredentialSource
StaticCredentials returns a source that always yields the same values.
Because a cookie is single use, a Conn built on this source can connect once. It is meant for a process iTerm2 launched — which is handed a cookie in its environment — and for tests.
type CredentialSourceFunc ¶
type CredentialSourceFunc func(ctx context.Context) (Credentials, error)
CredentialSourceFunc adapts a function to CredentialSource.
func (CredentialSourceFunc) Credentials ¶
func (f CredentialSourceFunc) Credentials(ctx context.Context) (Credentials, error)
Credentials calls f.
type Credentials ¶
Credentials authorise a connection to iTerm2's API.
The cookie is single use: iTerm2 consumes it during the WebSocket handshake (iTermWebSocketCookieJar consumeCookie), so a second connection needs a second cookie. The key is a stable identity for the client — iTerm2 reuses it to recognise a reconnecting script and offer the same authorisation, and invents one if it is absent.
type DurableSubscription ¶ added in v0.3.0
type DurableSubscription struct {
// contains filtered or unexported fields
}
DurableSubscription is a Subscription that a Persistent connection re-makes on every new connection, so DurableSubscription.C stays open across iTerm2 restarts. What iTerm2 posted while it was away is lost; a Reconnect says when that happened.
func (*DurableSubscription) C ¶ added in v0.3.0
func (d *DurableSubscription) C() <-chan *apipb.Notification
C is the channel notifications arrive on. It is closed by DurableSubscription.Unsubscribe, by Persistent.Close, or when the subscription cannot be re-made after a reconnect, in which case DurableSubscription.Err says why.
func (*DurableSubscription) Dropped ¶ added in v0.3.0
func (d *DurableSubscription) Dropped() uint64
Dropped counts notifications discarded because C was full, across every connection this subscription has had.
func (*DurableSubscription) Err ¶ added in v0.3.0
func (d *DurableSubscription) Err() error
Err is nil until the channel closes, and nil after an Unsubscribe or a Close. It is set when iTerm2 refused the subscription on a new connection — a per-session subscription whose session did not survive the restart, for one.
func (*DurableSubscription) Unsubscribe ¶ added in v0.3.0
func (d *DurableSubscription) Unsubscribe(ctx context.Context) error
Unsubscribe stops the subscription for good: it is not re-made at the next reconnect, and C is closed.
type Hierarchy ¶
type Hierarchy struct {
Windows []*Window
// BuriedSessions are sessions iTerm2 is holding without a tab. They have no
// frame or grid size, and no tab or window to reach them through.
BuriedSessions []*Session
}
Hierarchy is a snapshot of every window, tab and session iTerm2 had open when Conn.ListSessions was called.
It is a snapshot, not a live view: sessions open and close, so an id taken from here can be gone by the time it is used. Requests naming a vanished session come back as a *StatusError with a NOT_FOUND status.
func (*Hierarchy) Session ¶
Session finds a session by id, returning nil when the snapshot has no such session.
func (*Hierarchy) Sessions ¶
Sessions returns every session in the hierarchy, buried ones last.
It is the flat view most callers want: finding a session by its title or a variable does not usually care which window it is in.
type NewTab ¶
type NewTab struct {
WindowID string
// TabID is rendered as a decimal string because that is the form the rest of
// the API uses: api.proto types CreateTabResponse.tab_id as int32 while
// ListSessionsResponse.Tab.tab_id is a string. That the two are the same
// namespace is inferred from api.proto, not yet confirmed against a running
// iTerm2 — see ROADMAP.md.
TabID string
SessionID string
}
NewTab identifies what Conn.CreateTab created.
type Option ¶
type Option func(*config)
Option configures Connect.
func ForceTCP ¶
func ForceTCP() Option
ForceTCP connects over loopback TCP even when a unix socket exists.
func WithAdvisoryName ¶
WithAdvisoryName sets the name iTerm2 shows for this client in its script console and its authorisation prompt. It should name the program, not this library. The default is the running program's filename.
func WithCredentialSource ¶
func WithCredentialSource(src CredentialSource) Option
WithCredentialSource replaces how credentials are obtained. The default is DefaultCredentials.
func WithCredentials ¶
WithCredentials supplies a cookie and key directly, instead of reading the environment or asking iTerm2 over AppleScript. Use it when something else in the program already holds a cookie, and in tests.
func WithReconnectBackoff ¶ added in v0.3.0
WithReconnectBackoff sets how long a Persistent connection waits between attempts while iTerm2 is away: min after the first failure, doubling to max. The default is one second to thirty. Connect ignores it.
func WithSocketPath ¶
WithSocketPath overrides the unix domain socket to connect to. The default is DefaultSocketPath.
func WithSubscriptionBuffer ¶
WithSubscriptionBuffer sets how many notifications a Subscription buffers before it starts dropping them. The default is 64.
Notifications are dropped rather than blocking, because iTerm2 posts screen updates and keystrokes faster than most consumers read them, and a blocked reader would stall every other request on the connection. See Subscription.Dropped.
func WithTCPAddress ¶
WithTCPAddress overrides the loopback address used when no unix socket is present. The default is LegacyTCPAddress.
type Persistent ¶ added in v0.3.0
type Persistent struct {
// contains filtered or unexported fields
}
Persistent is a connection to iTerm2 that survives iTerm2 restarting, which it does on every update.
A Conn cannot come back: its cookie is spent. Persistent dials a fresh one when the current one ends, re-makes every DurableSubscription on it, and reports each replacement on Persistent.Reconnects. Between the two, calls return ErrReconnecting.
It is the loop the README used to ask every program to write.
func ConnectPersistent ¶ added in v0.3.0
func ConnectPersistent(ctx context.Context, opts ...Option) (*Persistent, error)
ConnectPersistent connects to iTerm2 as Connect does, with the same options, and keeps reconnecting with them until Persistent.Close.
ctx bounds the first connection only. Its error is returned as Connect's would be, so a program started with the API switched off finds out at once. Every attempt obtains fresh credentials from the configured source, which with the default credentials means asking iTerm2 for a new cookie.
func (*Persistent) Activate ¶ added in v0.4.0
func (p *Persistent) Activate(ctx context.Context, opts ActivateOptions) error
Activate is Conn.Activate on whichever connection is current. It returns ErrReconnecting while iTerm2 is away; see Persistent.
func (*Persistent) Close ¶ added in v0.3.0
func (p *Persistent) Close() error
Close stops reconnecting, closes the current connection and every DurableSubscription. Calling it twice is harmless.
func (*Persistent) CloseSessions ¶ added in v0.4.0
CloseSessions is Conn.CloseSessions on whichever connection is current. It returns ErrReconnecting while iTerm2 is away; see Persistent.
func (*Persistent) CloseTabs ¶ added in v0.4.0
CloseTabs is Conn.CloseTabs on whichever connection is current. It returns ErrReconnecting while iTerm2 is away; see Persistent.
func (*Persistent) CloseWindows ¶ added in v0.4.0
CloseWindows is Conn.CloseWindows on whichever connection is current. It returns ErrReconnecting while iTerm2 is away; see Persistent.
func (*Persistent) Conn ¶ added in v0.3.0
func (p *Persistent) Conn() (*Conn, error)
Conn returns the current connection, for the typed methods on Conn. It returns ErrReconnecting while iTerm2 is away and ErrClosed after Close. Do not keep the result: it is replaced at the next reconnect.
func (*Persistent) CreateTab ¶ added in v0.4.0
func (p *Persistent) CreateTab(ctx context.Context, opts CreateTabOptions) (*NewTab, error)
CreateTab is Conn.CreateTab on whichever connection is current. It returns ErrReconnecting while iTerm2 is away; see Persistent.
func (*Persistent) Do ¶ added in v0.3.0
func (p *Persistent) Do(ctx context.Context, req *apipb.ClientOriginatedMessage) (*apipb.ServerOriginatedMessage, error)
Do sends one request on the current connection. See Conn.Do.
func (*Persistent) GetStringVariable ¶ added in v0.4.0
func (p *Persistent) GetStringVariable(ctx context.Context, scope VariableScope, identifier, name string) (value string, ok bool, err error)
GetStringVariable is Conn.GetStringVariable on whichever connection is current. It returns ErrReconnecting while iTerm2 is away; see Persistent.
func (*Persistent) GetVariables ¶ added in v0.4.0
func (p *Persistent) GetVariables(ctx context.Context, scope VariableScope, identifier string, names ...string) (map[string]json.RawMessage, error)
GetVariables is Conn.GetVariables on whichever connection is current. It returns ErrReconnecting while iTerm2 is away; see Persistent.
func (*Persistent) ListSessions ¶ added in v0.4.0
func (p *Persistent) ListSessions(ctx context.Context) (*Hierarchy, error)
ListSessions is Conn.ListSessions on whichever connection is current. It returns ErrReconnecting while iTerm2 is away; see Persistent.
func (*Persistent) Reconnects ¶ added in v0.3.0
func (p *Persistent) Reconnects() <-chan Reconnect
Reconnects delivers a Reconnect each time the connection is replaced. It holds only the latest; see Reconnect.Count.
func (*Persistent) RegisterContextMenuItem ¶ added in v0.9.0
func (p *Persistent) RegisterContextMenuItem(ctx context.Context, m ContextMenuItem) (*RPCRegistration, error)
RegisterContextMenuItem is Conn.RegisterContextMenuItem on a Persistent: the item is registered again on every new connection.
func (*Persistent) RegisterRPC ¶ added in v0.7.0
func (p *Persistent) RegisterRPC(ctx context.Context, fn RPC) (*RPCRegistration, error)
RegisterRPC is Conn.RegisterRPC on a Persistent: the registration is a DurableSubscription, so the function is registered again on every new connection and answers on whichever connection is current.
func (*Persistent) RegisterTitleProvider ¶ added in v0.8.0
func (p *Persistent) RegisterTitleProvider(ctx context.Context, t TitleProvider) (*RPCRegistration, error)
RegisterTitleProvider is Conn.RegisterTitleProvider on a Persistent: it is registered again on every new connection.
func (*Persistent) RegisterTool ¶ added in v0.6.0
func (p *Persistent) RegisterTool(ctx context.Context, t Tool) error
RegisterTool is Conn.RegisterTool, and the tool is registered again on every new connection, before the Reconnect is announced. iTerm2 forgets a tool when it quits, so without this a panel vanishes at every restart.
Re-registration does not reveal the tool, whatever Reveal says: a restart of iTerm2 should not pop the toolbelt open. A tool iTerm2 refuses then is reported in Reconnect.ToolErr. Registering a tool with the same Identifier again replaces it, here as in iTerm2.
Like every call, it returns ErrReconnecting while iTerm2 is away, and the tool is then not remembered.
func (*Persistent) SendText ¶ added in v0.4.0
func (p *Persistent) SendText(ctx context.Context, sessionID, text string, suppressBroadcast bool) error
SendText is Conn.SendText on whichever connection is current. It returns ErrReconnecting while iTerm2 is away; see Persistent.
func (*Persistent) SetStringVariable ¶ added in v0.4.0
func (p *Persistent) SetStringVariable(ctx context.Context, scope VariableScope, identifier, name, value string) error
SetStringVariable is Conn.SetStringVariable on whichever connection is current. It returns ErrReconnecting while iTerm2 is away; see Persistent.
func (*Persistent) SetVariables ¶ added in v0.4.0
func (p *Persistent) SetVariables(ctx context.Context, scope VariableScope, identifier string, values map[string]string) error
SetVariables is Conn.SetVariables on whichever connection is current. It returns ErrReconnecting while iTerm2 is away; see Persistent.
func (*Persistent) SplitPane ¶ added in v0.4.0
func (p *Persistent) SplitPane(ctx context.Context, sessionID string, opts SplitPaneOptions) ([]string, error)
SplitPane is Conn.SplitPane on whichever connection is current. It returns ErrReconnecting while iTerm2 is away; see Persistent.
func (*Persistent) Subscribe ¶ added in v0.3.0
func (p *Persistent) Subscribe(ctx context.Context, req *apipb.NotificationRequest) (*DurableSubscription, error)
Subscribe asks iTerm2 to post notifications, as Conn.Subscribe does, and re-asks on every new connection.
func (*Persistent) SubscribeFocusChanges ¶ added in v0.4.0
func (p *Persistent) SubscribeFocusChanges(ctx context.Context) (*DurableSubscription, error)
SubscribeFocusChanges is Conn.SubscribeFocusChanges on a Persistent.
func (*Persistent) SubscribeLayoutChanges ¶ added in v0.4.0
func (p *Persistent) SubscribeLayoutChanges(ctx context.Context) (*DurableSubscription, error)
SubscribeLayoutChanges is Conn.SubscribeLayoutChanges on a Persistent.
func (*Persistent) SubscribeNewSessions ¶ added in v0.3.0
func (p *Persistent) SubscribeNewSessions(ctx context.Context) (*DurableSubscription, error)
SubscribeNewSessions is Conn.SubscribeNewSessions on a Persistent.
func (*Persistent) SubscribeTerminatedSessions ¶ added in v0.3.0
func (p *Persistent) SubscribeTerminatedSessions(ctx context.Context) (*DurableSubscription, error)
SubscribeTerminatedSessions is Conn.SubscribeTerminatedSessions on a Persistent.
func (*Persistent) SubscribeVariableChanges ¶ added in v0.4.0
func (p *Persistent) SubscribeVariableChanges(ctx context.Context, scope VariableScope, identifier, name string) (*DurableSubscription, error)
SubscribeVariableChanges is Conn.SubscribeVariableChanges on a Persistent.
type RPC ¶ added in v0.7.0
type RPC struct {
// Name is what iTerm2 calls it by.
Name string
// Arguments are the argument names, which with Name make the signature
// iTerm2 matches a call against.
Arguments []string
// Defaults fills an argument the caller left out from an iTerm2 variable,
// by path: {"session_id": "session.id"}. Each key must be in Arguments.
Defaults map[string]string
// Timeout is how long iTerm2 waits for an answer. Zero leaves it to iTerm2.
Timeout time.Duration
// Handler answers one call. Each argument arrives as the JSON iTerm2 sent;
// the result is sent back as JSON, and an error as an exception iTerm2 can
// show. ctx ends when the registration does.
Handler func(ctx context.Context, args map[string]json.RawMessage) (any, error)
}
RPC is a function iTerm2 can call in this program: from a key binding, a trigger, a toolbelt panel's page, or anything else that invokes a script function by name, such as `greet(who: "you")`.
This registers it in iTerm2's generic role. The status-bar, session-title and context-menu roles take attributes of their own and are not covered yet.
type RPCRegistration ¶ added in v0.7.0
type RPCRegistration struct {
// contains filtered or unexported fields
}
RPCRegistration is a registered RPC. Unregister it to stop answering.
func (*RPCRegistration) Unregister ¶ added in v0.7.0
func (r *RPCRegistration) Unregister(ctx context.Context) error
Unregister stops the function. Calls already running are cancelled and waited for.
type Reconnect ¶ added in v0.3.0
type Reconnect struct {
// Count is how many reconnects this Persistent has made, this one included.
// The channel keeps only the latest, so a caller that fell behind sees the
// count jump rather than every event.
Count int
// Cause is why the previous connection ended. It wraps ErrClosed.
Cause error
// At is when the new connection was ready.
At time.Time
// ToolErr joins the errors of the tools that could not be registered again
// on the new connection (see [Persistent.RegisterTool]), or is nil.
ToolErr error
}
Reconnect reports that a Persistent connection was replaced.
Notifications iTerm2 posted between the old connection ending and the new one subscribing are gone, and nothing replays them. Treat a Reconnect as "my view of iTerm2 may be stale": resynchronise, for instance with Conn.ListSessions. It is sent only once every subscription is back, so a change made after the resynchronisation is delivered.
type Session ¶
type Session struct {
ID string
Title string
// Frame and GridSize are unset for a buried session, because it is not on
// screen to have either.
Frame Rect
GridSize Size
// Buried reports whether iTerm2 is holding this session without a tab.
Buried bool
// contains filtered or unexported fields
}
Session is one pane.
func (*Session) Activate ¶
func (s *Session) Activate(ctx context.Context, opts ActivateOptions) error
Activate selects this session and, with ActivateOptions, raises its tab, window and application.
func (*Session) SetVariable ¶
SetVariable writes one of this session's variables. The name must begin with "user.".
type SplitDirection ¶
type SplitDirection int32
SplitDirection is which way a pane divides.
const ( // SplitVertical puts the new pane beside the old one, divided by a vertical // line. api.proto names the divider, not the arrangement. SplitVertical SplitDirection = SplitDirection(apipb.SplitPaneRequest_VERTICAL) // SplitHorizontal puts the new pane above or below the old one. SplitHorizontal SplitDirection = SplitDirection(apipb.SplitPaneRequest_HORIZONTAL) )
type SplitNode ¶ added in v0.5.0
type SplitNode struct {
// Session is set when this node is a pane, and nil when it is a split.
Session *Session
// Vertical is the direction of this split's dividers: true when they are
// vertical, so Children sit side by side, left to right; false when they
// are horizontal, so Children are stacked, top to bottom.
Vertical bool
// Children are the areas this split divides, in order. Empty for a pane.
Children []*SplitNode
}
SplitNode is one node of a tab's split tree, as api.proto's SplitTreeNode lays it out: either a pane, or a divided area holding further nodes.
It carries no geometry of its own. Each pane's Frame and GridSize are on its Session, and anything more (proportions, divider positions) is not something iTerm2 reports.
func (*SplitNode) Panes ¶ added in v0.5.0
Panes returns the panes under n, depth first in link order, which is the order Tab.Sessions has.
type SplitPaneOptions ¶
type SplitPaneOptions struct {
Direction SplitDirection
// Before puts the new pane above or to the left of the one being split.
Before bool
// ProfileName selects the profile. Empty uses the default profile.
ProfileName string
// CustomProfileProperties overrides profile settings for the new session
// only. Values are JSON; see [CreateTabOptions.CustomProfileProperties].
CustomProfileProperties map[string]string
}
SplitPaneOptions configures Conn.SplitPane.
type StatusError ¶
StatusError reports a well-formed request that iTerm2 declined, carrying the status enum it answered with.
Op names the operation as this package spells it, so the error reads in Go terms; Status is iTerm2's own enum value name, so it can be looked up in api.proto.
func (*StatusError) Error ¶
func (e *StatusError) Error() string
type Subscription ¶
type Subscription struct {
// contains filtered or unexported fields
}
Subscription delivers one kind of notification from iTerm2.
iTerm2 posts every notification a connection has subscribed to down the one socket, with nothing tying a notification back to the request that asked for it. A Subscription therefore remembers what it asked for and delivers only the notifications that match, so two subscriptions on one Conn do not see each other's traffic.
iTerm2 refuses a second subscription to the same notification type and session on one connection, answering ALREADY_SUBSCRIBED; Conn.Subscribe surfaces that as a *StatusError. Fan one Subscription out in your own code, or use a second Conn.
func (*Subscription) C ¶
func (s *Subscription) C() <-chan *apipb.Notification
C is the channel notifications arrive on. It is closed when the subscription ends, whether through Subscription.Unsubscribe or because the connection went away.
func (*Subscription) Dropped ¶
func (s *Subscription) Dropped() uint64
Dropped counts notifications discarded because the buffer was full. A non-zero value means the consumer is slower than iTerm2 is posting; see WithSubscriptionBuffer.
func (*Subscription) Unsubscribe ¶
func (s *Subscription) Unsubscribe(ctx context.Context) error
Unsubscribe tells iTerm2 to stop posting this notification and closes Subscription.C.
The channel is closed even when the request fails — there is nothing left to deliver either way — so the returned error reports what iTerm2 said and is safe to log rather than handle. Calling it twice is harmless.
type Tab ¶
type Tab struct {
ID string
// WindowID is the window this tab was found in. api.proto does not carry it
// on the tab; it is filled in from the enclosing window while parsing, so
// that a *Tab is usable on its own.
WindowID string
// ActiveSessionID is the pane with focus within this tab. Reported from
// protocol 1.18; empty on older versions.
ActiveSessionID string
// TmuxWindowID and TmuxConnectionID are set only for a tab belonging to a
// tmux integration session.
TmuxWindowID string
TmuxConnectionID string
// Group describes the tab group this tab belongs to, or nil when it belongs
// to none. Reported from protocol 1.19.
Group *TabGroup
// Sessions are the tab's panes, flattened from api.proto's split tree in
// left-to-right, top-to-bottom order. [Tab.SplitTree] keeps the tree's
// shape.
Sessions []*Session
// MinimizedSessions are panes the user has collapsed. They are not in
// Sessions.
MinimizedSessions []*Session
// contains filtered or unexported fields
}
Tab is one tab within a window.
func (*Tab) Activate ¶
func (t *Tab) Activate(ctx context.Context, opts ActivateOptions) error
Activate selects this tab.
func (*Tab) ActiveSession ¶
ActiveSession returns the tab's focused pane, or nil when iTerm2 did not say which it is — which is what an iTerm2 older than protocol 1.18 does.
type TabGroup ¶
type TabGroup struct {
ID string
Name string
// Color is a hex string as iTerm2 produces it: "#rrggbb" for sRGB, or
// "p3#rrggbbrrggbb" for Display P3.
Color string
Collapsed bool
}
TabGroup is the group a tab belongs to.
A group has no central record in iTerm2: its identity is a UUID carried by each member tab, and every member reports the same name, colour and collapsed state. Two tabs are in the same group exactly when their IDs match.
type TitleProvider ¶ added in v0.8.0
type TitleProvider struct {
RPC
// DisplayName is how iTerm2 lists the provider in its settings.
DisplayName string
// Identifier must be unique among title providers; api.proto asks for a
// reverse-DNS name, such as com.example.branch-title.
Identifier string
}
TitleProvider is an RPC iTerm2 calls to compute a session's title. Once registered it appears among the title choices in a profile's settings, under DisplayName, and a session using it shows whatever its Handler returns.
Defaults is how a title follows the session: map an argument to a variable such as "session.path" or "user.gitBranch", and iTerm2 calls the provider again when that variable changes.
type Tool ¶ added in v0.6.0
type Tool struct {
// Name is shown to the user.
Name string
// Identifier must be unique to the tool. api.proto asks for a reverse-DNS
// name, such as com.example.mytool. Registering the same identifier again
// replaces the tool.
Identifier string
// URL is the page the panel loads.
URL string
// Reveal shows the tool even if it was registered before. iTerm2 adds a
// tool to the visible set by itself only the first time; it does not open
// a hidden toolbelt either way.
Reveal bool
}
Tool is a panel in iTerm2's toolbelt, showing a web page.
type VariableScope ¶
type VariableScope int32
VariableScope selects which object a variable belongs to.
The values mirror api.proto's VariableScope enum, which starts at 1 — there is no zero value, so a VariableScope left at its Go zero is invalid and the methods taking one reject it rather than defaulting to a scope the caller did not choose.
const ( ScopeSession VariableScope = VariableScope(apipb.VariableScope_SESSION) ScopeTab VariableScope = VariableScope(apipb.VariableScope_TAB) ScopeWindow VariableScope = VariableScope(apipb.VariableScope_WINDOW) ScopeApp VariableScope = VariableScope(apipb.VariableScope_APP) )
func (VariableScope) String ¶
func (s VariableScope) String() string
String names the scope as api.proto spells it.
type Window ¶
type Window struct {
ID string
Number int32
Frame Rect
// SelectedTabID is the tab on top. iTerm2 began reporting it in protocol
// 1.18 and leaves it empty on older versions.
SelectedTabID string
Tabs []*Tab
// contains filtered or unexported fields
}
Window is one iTerm2 window.