(svloc VLoc)
| 143 | } |
| 144 | |
| 145 | func (w *BufWindow) getLocFromVLoc(svloc VLoc) buffer.Loc { |
| 146 | loc := buffer.Loc{X: 0, Y: svloc.Line} |
| 147 | |
| 148 | if w.bufWidth <= 0 { |
| 149 | return loc |
| 150 | } |
| 151 | |
| 152 | wordwrap := w.Buf.Settings["wordwrap"].(bool) |
| 153 | tabsize := util.IntOpt(w.Buf.Settings["tabsize"]) |
| 154 | |
| 155 | line := w.Buf.LineBytes(svloc.Line) |
| 156 | vloc := VLoc{SLoc: SLoc{svloc.Line, 0}, VisualX: 0} |
| 157 | |
| 158 | totalwidth := 0 |
| 159 | |
| 160 | var widths []int |
| 161 | if wordwrap { |
| 162 | widths = make([]int, 0, w.bufWidth) |
| 163 | } else { |
| 164 | widths = make([]int, 0, 1) |
| 165 | } |
| 166 | wordwidth := 0 |
| 167 | |
| 168 | for len(line) > 0 { |
| 169 | r, _, size := util.DecodeCharacter(line) |
| 170 | line = line[size:] |
| 171 | |
| 172 | width := 0 |
| 173 | switch r { |
| 174 | case '\t': |
| 175 | ts := tabsize - (totalwidth % tabsize) |
| 176 | width = util.Min(ts, w.bufWidth-vloc.VisualX) |
| 177 | totalwidth += ts |
| 178 | default: |
| 179 | width = runewidth.RuneWidth(r) |
| 180 | totalwidth += width |
| 181 | } |
| 182 | |
| 183 | widths = append(widths, width) |
| 184 | wordwidth += width |
| 185 | |
| 186 | // Collect a complete word to know its width. |
| 187 | // If wordwrap is off, every single character is a complete "word". |
| 188 | if wordwrap { |
| 189 | if !util.IsWhitespace(r) && len(line) > 0 && wordwidth < w.bufWidth { |
| 190 | continue |
| 191 | } |
| 192 | } |
| 193 | |
| 194 | // If a word (or just a wide rune) does not fit in the window |
| 195 | if vloc.VisualX+wordwidth > w.bufWidth && vloc.VisualX > 0 { |
| 196 | if vloc.Row == svloc.Row { |
| 197 | if wordwrap { |
| 198 | // it's a word, not a wide rune |
| 199 | loc.X-- |
| 200 | } |
| 201 | return loc |
| 202 | } |
no test coverage detected