okami.mom/ultraviolet
git clone https://git.nkp.pet/okami.mom/ultraviolet
b3a6f4b
upstream
1package uv 2 3// DefaultTabInterval is the default tab interval. 4const DefaultTabInterval = 8 5 6// TabStops represents horizontal line tab stops. 7type TabStops struct { 8stops []int 9interval int 10width int 11} 12 13// NewTabStops creates a new set of tab stops from a number of columns and an 14// interval. 15func NewTabStops (width ,interval int )* TabStops { 16ts := new (TabStops ) 17ts .interval = interval 18ts .width = width 19ts .stops = make ([]int , (width + (interval - 1 ))/ interval ) 20ts .init (0 ,width ) 21return ts 22} 23 24// DefaultTabStops creates a new set of tab stops with the default interval. 25func DefaultTabStops (cols int )* TabStops { 26return NewTabStops (cols ,DefaultTabInterval ) 27} 28 29// Resize resizes the tab stops to the given width. 30func (ts * TabStops )Resize (width int ) { 31if width == ts .width { 32return 33 } 34 35if width < ts .width { 36size := (width + (ts .interval - 1 ))/ ts .interval 37ts .stops = ts .stops [:size ] 38 }else { 39size := (width - ts .width + (ts .interval - 1 ))/ ts .interval 40ts .stops = append (ts .stops ,make ([]int ,size )... ) 41 } 42 43ts .init (ts .width ,width ) 44ts .width = width 45} 46 47// Width returns the width of the screen that the tab stops are set for. 48func (ts * TabStops )Width ()int { 49return ts .width 50} 51 52// IsStop returns true if the given column is a tab stop. 53func (ts TabStops )IsStop (col int )bool { 54mask := ts .mask (col ) 55i := col >> 3 56if i < 0 || i >= len (ts .stops ) { 57return false 58 } 59return ts .stops [i ]& mask != 0 60} 61 62// Next returns the next tab stop after the given column. 63func (ts TabStops )Next (col int )int { 64return ts .Find (col ,1 ) 65} 66 67// Prev returns the previous tab stop before the given column. 68func (ts TabStops )Prev (col int )int { 69return ts .Find (col ,- 1 ) 70} 71 72// Find returns the prev/next tab stop before/after the given column and delta. 73// If delta is positive, it returns the next tab stop after the given column. 74// If delta is negative, it returns the previous tab stop before the given column. 75// If delta is zero, it returns the given column. 76func (ts TabStops )Find (col ,delta int )int { 77if delta == 0 { 78return col 79 } 80 81var prev bool 82count := delta 83if count < 0 { 84count = - count 85prev = true 86 } 87 88for count > 0 { 89if ! prev { 90if col >= ts .width - 1 { 91return col 92 } 93 94col ++ 95 }else { 96if col < 1 { 97return col 98 } 99 100col -- 101 } 102 103if ts .IsStop (col ) { 104count -- 105 } 106 } 107 108return col 109} 110 111// Set adds a tab stop at the given column. 112func (ts * TabStops )Set (col int ) { 113mask := ts .mask (col ) 114ts .stops [col >> 3 ]|= mask 115} 116 117// Reset removes the tab stop at the given column. 118func (ts * TabStops )Reset (col int ) { 119mask := ts .mask (col ) 120ts .stops [col >> 3 ]&= ^ mask 121} 122 123// Clear removes all tab stops. 124func (ts * TabStops )Clear () { 125ts .stops = make ([]int ,len (ts .stops )) 126} 127 128// mask returns the mask for the given column. 129func (ts * TabStops )mask (col int )int { 130return 1 << (col & (ts .interval - 1 )) 131} 132 133// init initializes the tab stops starting from col until width. 134func (ts * TabStops )init (col ,width int ) { 135for x := col ;x < width ;x ++ { 136if x % ts .interval == 0 { 137ts .Set (x ) 138 }else { 139ts .Reset (x ) 140 } 141 } 142}