Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
0284bd652a | ||
|
|
c82251169f | ||
|
|
f065464e2c | ||
|
|
534e7da40d | ||
|
|
96ce8cef8d | ||
|
|
052945f9f8 | ||
|
|
aff8e0572a |
@@ -158,7 +158,8 @@ func (s *session) recvLoop() {
|
|||||||
t := s.client.Transport()
|
t := s.client.Transport()
|
||||||
oldNum := t.LastRecvOldNum()
|
oldNum := t.LastRecvOldNum()
|
||||||
newNum := t.LastRecvNewNum()
|
newNum := t.LastRecvNewNum()
|
||||||
s.tracker.applyDiff(diff, oldNum, newNum)
|
throwawayNum := t.ThrowawayNum()
|
||||||
|
s.tracker.applyDiff(diff, oldNum, newNum, throwawayNum)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+16
-30
@@ -41,7 +41,8 @@ func newStateTracker(cols, rows int) *stateTracker {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// applyDiff processes an incoming server diff using state tracking.
|
// applyDiff processes an incoming server diff using state tracking.
|
||||||
func (st *stateTracker) applyDiff(diff []byte, oldNum, newNum uint64) {
|
// throwawayNum is the server's indication of which states it no longer references.
|
||||||
|
func (st *stateTracker) applyDiff(diff []byte, oldNum, newNum, throwawayNum uint64) {
|
||||||
st.mu.Lock()
|
st.mu.Lock()
|
||||||
defer st.mu.Unlock()
|
defer st.mu.Unlock()
|
||||||
|
|
||||||
@@ -60,11 +61,13 @@ func (st *stateTracker) applyDiff(diff []byte, oldNum, newNum uint64) {
|
|||||||
// Need the base state to apply the diff.
|
// Need the base state to apply the diff.
|
||||||
base, ok := st.states[oldNum]
|
base, ok := st.states[oldNum]
|
||||||
if !ok {
|
if !ok {
|
||||||
return
|
// After a resize we have no states. Start fresh with a
|
||||||
}
|
// clean emulator so the first post-resize diff works.
|
||||||
|
st.shadow = vt.NewEmulator(st.cols, st.rows)
|
||||||
// Restore shadow to base state if needed.
|
st.shadowState = oldNum
|
||||||
if st.shadowState != oldNum {
|
base = mosh.SnapshotEmulator(st.shadow, true)
|
||||||
|
st.states[oldNum] = base
|
||||||
|
} else if st.shadowState != oldNum {
|
||||||
st.shadow = vt.NewEmulator(st.cols, st.rows)
|
st.shadow = vt.NewEmulator(st.cols, st.rows)
|
||||||
// Write the base framebuffer as ANSI to restore state.
|
// Write the base framebuffer as ANSI to restore state.
|
||||||
if base != nil {
|
if base != nil {
|
||||||
@@ -91,9 +94,13 @@ func (st *stateTracker) applyDiff(diff []byte, oldNum, newNum uint64) {
|
|||||||
st.latestState = newNum
|
st.latestState = newNum
|
||||||
}
|
}
|
||||||
|
|
||||||
// Bound states list.
|
// Prune states the server no longer references.
|
||||||
if len(st.states) > 128 {
|
if throwawayNum > 0 {
|
||||||
st.pruneStates()
|
for n := range st.states {
|
||||||
|
if n < throwawayNum {
|
||||||
|
delete(st.states, n)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Display diff: compute ANSI difference between displayed and latest.
|
// Display diff: compute ANSI difference between displayed and latest.
|
||||||
@@ -131,24 +138,3 @@ func (st *stateTracker) resize(cols, rows int) {
|
|||||||
st.displayedFB = nil
|
st.displayedFB = nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (st *stateTracker) pruneStates() {
|
|
||||||
if len(st.states) <= 64 {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
// Keep the 64 most recent states.
|
|
||||||
var nums []uint64
|
|
||||||
for n := range st.states {
|
|
||||||
nums = append(nums, n)
|
|
||||||
}
|
|
||||||
// Simple sort for small lists.
|
|
||||||
for i := range nums {
|
|
||||||
for j := i + 1; j < len(nums); j++ {
|
|
||||||
if nums[j] < nums[i] {
|
|
||||||
nums[i], nums[j] = nums[j], nums[i]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
for _, n := range nums[:len(nums)-64] {
|
|
||||||
delete(st.states, n)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|||||||
+6
-4
@@ -15,8 +15,10 @@ const (
|
|||||||
attrFaint = 1 << 1
|
attrFaint = 1 << 1
|
||||||
attrItalic = 1 << 2
|
attrItalic = 1 << 2
|
||||||
attrBlink = 1 << 3
|
attrBlink = 1 << 3
|
||||||
attrReverse = 1 << 4
|
attrRapidBlink = 1 << 4
|
||||||
attrStrikethrough = 1 << 5
|
attrReverse = 1 << 5
|
||||||
|
attrConceal = 1 << 6
|
||||||
|
attrStrikethrough = 1 << 7
|
||||||
)
|
)
|
||||||
|
|
||||||
// Framebuffer represents a terminal screen state for mosh SSP.
|
// Framebuffer represents a terminal screen state for mosh SSP.
|
||||||
@@ -172,11 +174,11 @@ func (fb *Framebuffer) fullRedraw() []byte {
|
|||||||
buf = append(buf, "\r\n"...)
|
buf = append(buf, "\r\n"...)
|
||||||
}
|
}
|
||||||
rowOff := y * fb.W
|
rowOff := y * fb.W
|
||||||
// Track trailing spaces to avoid sending them.
|
// Track trailing default-attr spaces to avoid sending them.
|
||||||
lastNonSpace := -1
|
lastNonSpace := -1
|
||||||
for x := fb.W - 1; x >= 0; x-- {
|
for x := fb.W - 1; x >= 0; x-- {
|
||||||
c := &fb.Cells[rowOff+x]
|
c := &fb.Cells[rowOff+x]
|
||||||
if c.Rune != ' ' || c.Rune == 0 || c.Attr != (Attr{}) {
|
if (c.Rune != ' ' && c.Rune != 0) || c.Attr != (Attr{}) {
|
||||||
lastNonSpace = x
|
lastNonSpace = x
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -379,6 +379,14 @@ func (t *Transport) LastRecvNewNum() uint64 {
|
|||||||
return t.lastRecvNewNum
|
return t.lastRecvNewNum
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ThrowawayNum returns the server's throwaway number — states below this
|
||||||
|
// are no longer referenced by the server and can be safely pruned.
|
||||||
|
func (t *Transport) ThrowawayNum() uint64 {
|
||||||
|
t.mu.Lock()
|
||||||
|
defer t.mu.Unlock()
|
||||||
|
return t.throwawayNum
|
||||||
|
}
|
||||||
|
|
||||||
// LastRecv returns the time of the last received datagram.
|
// LastRecv returns the time of the last received datagram.
|
||||||
func (t *Transport) LastRecv() time.Time {
|
func (t *Transport) LastRecv() time.Time {
|
||||||
t.mu.Lock()
|
t.mu.Lock()
|
||||||
|
|||||||
Reference in New Issue
Block a user