├── README.md └── cmd └── gol ├── main.go └── w32con.go /README.md: -------------------------------------------------------------------------------- 1 | # gol-cmd 2 | 3 | ![](http://i.imgur.com/lPF8Gtd.gif) 4 | 5 | ## Usage 6 | 7 | ``` 8 | gol 9 | ``` 10 | 11 | NOTE) しらじらしく ls コマンドと間違えなさい。 12 | 13 | ## Installation 14 | 15 | ``` 16 | $ go get github.com/mattn/gol-cmd/cmd/gol 17 | ``` 18 | 19 | ## License 20 | 21 | MIT 22 | 23 | ## Author 24 | 25 | Yasuhiro Matsumoto (a.k.a mattn) 26 | -------------------------------------------------------------------------------- /cmd/gol/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "io" 6 | "os" 7 | "time" 8 | ) 9 | 10 | var out io.Writer = os.Stdout 11 | 12 | func main() { 13 | fmt.Fprintln(out, "\x1b[2J") 14 | for i := 75; i > 0; i-- { 15 | fmt.Fprintf(out, "\x1b[10;%dH\x1bK", i) 16 | fmt.Print(`ʕ◔ϖ◔ʔ `) 17 | time.Sleep(50 * time.Millisecond) 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /cmd/gol/w32con.go: -------------------------------------------------------------------------------- 1 | // +build windows 2 | 3 | package main 4 | 5 | import ( 6 | "bytes" 7 | "fmt" 8 | "os" 9 | "strconv" 10 | "strings" 11 | "syscall" 12 | "unsafe" 13 | ) 14 | 15 | const ( 16 | foregroundBlue = 0x1 17 | foregroundGreen = 0x2 18 | foregroundRed = 0x4 19 | foregroundIntensity = 0x8 20 | foregroundMask = (foregroundRed | foregroundBlue | foregroundGreen | foregroundIntensity) 21 | backgroundBlue = 0x10 22 | backgroundGreen = 0x20 23 | backgroundRed = 0x40 24 | backgroundIntensity = 0x80 25 | backgroundMask = (backgroundRed | backgroundBlue | backgroundGreen | backgroundIntensity) 26 | ) 27 | 28 | var kernel32 = syscall.NewLazyDLL("kernel32.dll") 29 | 30 | var ( 31 | procGetStdHandle = kernel32.NewProc("GetStdHandle") 32 | procGetConsoleScreenBufferInfo = kernel32.NewProc("GetConsoleScreenBufferInfo") 33 | procGetConsoleCursorInfo = kernel32.NewProc("GetConsoleCursorInfo") 34 | procSetConsoleCursorPosition = kernel32.NewProc("SetConsoleCursorPosition") 35 | procFillConsoleOutputCharacter = kernel32.NewProc("FillConsoleOutputCharacterW") 36 | procFillConsoleOutputAttribute = kernel32.NewProc("FillConsoleOutputAttribute") 37 | procSetConsoleTextAttribute = kernel32.NewProc("SetConsoleTextAttribute") 38 | procScrollConsoleScreenBuffer = kernel32.NewProc("ScrollConsoleScreenBufferW") 39 | ) 40 | 41 | type wchar uint16 42 | type short int16 43 | type dword uint32 44 | type word uint16 45 | 46 | type coord struct { 47 | x short 48 | y short 49 | } 50 | 51 | type smallRect struct { 52 | left short 53 | top short 54 | right short 55 | bottom short 56 | } 57 | 58 | type consoleScreenBufferInfo struct { 59 | size coord 60 | cursorPosition coord 61 | attributes word 62 | window smallRect 63 | maximumWindowSize coord 64 | } 65 | 66 | type consoleCursorInfo struct { 67 | size dword 68 | visible int32 69 | } 70 | 71 | type charInfo struct { 72 | unicodeChar wchar 73 | attributes word 74 | } 75 | 76 | type WindowsConsoleWriter struct { 77 | out syscall.Handle 78 | } 79 | 80 | func (w *WindowsConsoleWriter) Write(b []byte) (int, error) { 81 | var csbi consoleScreenBufferInfo 82 | procGetConsoleScreenBufferInfo.Call(uintptr(w.out), uintptr(unsafe.Pointer(&csbi))) 83 | attr_old := csbi.attributes 84 | defer func() { 85 | procSetConsoleTextAttribute.Call(uintptr(w.out), uintptr(attr_old)) 86 | }() 87 | 88 | var lastbuf bytes.Buffer 89 | var scroll *smallRect 90 | 91 | er := bytes.NewBuffer(b) 92 | for { 93 | r1, _, err := procGetConsoleScreenBufferInfo.Call(uintptr(w.out), uintptr(unsafe.Pointer(&csbi))) 94 | if r1 == 0 { 95 | break 96 | } 97 | 98 | c1, _, err := er.ReadRune() 99 | if err != nil { 100 | break 101 | } 102 | if c1 != 0x1b { 103 | switch { 104 | case c1 == 0x08: 105 | if csbi.cursorPosition.x > 0 { 106 | csbi.cursorPosition.x -= 1 107 | } 108 | r1, _, _ := procSetConsoleCursorPosition.Call(uintptr(w.out), uintptr(*(*int32)(unsafe.Pointer(&csbi.cursorPosition)))) 109 | if r1 == 0 { 110 | break 111 | } 112 | case c1 == 0x0a: 113 | if scroll != nil && csbi.cursorPosition.y == scroll.bottom { 114 | var ci charInfo 115 | ci.unicodeChar = ' ' 116 | ci.attributes = csbi.attributes 117 | move := scroll 118 | move.top++ 119 | xy := coord{ 120 | x: 0, 121 | y: scroll.top, 122 | } 123 | r1, _, _ = procScrollConsoleScreenBuffer.Call(uintptr(w.out), uintptr(unsafe.Pointer(&move)), 0, uintptr(*(*int32)(unsafe.Pointer(&xy))), uintptr(unsafe.Pointer(&ci))) 124 | if r1 == 0 { 125 | break 126 | } 127 | } else if csbi.cursorPosition.y < csbi.window.bottom { 128 | csbi.cursorPosition.y++ 129 | r1, _, _ := procSetConsoleCursorPosition.Call(uintptr(w.out), uintptr(*(*int32)(unsafe.Pointer(&csbi.cursorPosition)))) 130 | if r1 == 0 { 131 | break 132 | } 133 | } else { 134 | fmt.Print(string(c1)) 135 | } 136 | case c1 == '\r' || c1 == '\t' || c1 >= 0x20: 137 | fmt.Print(string(c1)) 138 | } 139 | continue 140 | } 141 | c2, _, err := er.ReadRune() 142 | if err != nil { 143 | lastbuf.WriteRune(c1) 144 | break 145 | } 146 | 147 | var buf bytes.Buffer 148 | var m rune 149 | switch c2 { 150 | case 0x5b: 151 | for { 152 | c, _, err := er.ReadRune() 153 | if err != nil { 154 | lastbuf.WriteRune(c1) 155 | lastbuf.WriteByte(0x5b) 156 | lastbuf.Write(buf.Bytes()) 157 | break 158 | } 159 | if ('a' <= c && c <= 'z') || ('A' <= c && c <= 'Z') || c == '@' { 160 | m = c 161 | break 162 | } 163 | buf.Write([]byte(string(c))) 164 | } 165 | case 0x5d: 166 | for { 167 | c, _, err := er.ReadRune() 168 | if err != nil { 169 | lastbuf.Write(buf.Bytes()) 170 | break 171 | } 172 | if c == ';' { 173 | break 174 | } 175 | buf.Write([]byte(string(c))) 176 | } 177 | continue 178 | } 179 | 180 | var n int 181 | switch m { 182 | case 'h': 183 | if _, err := fmt.Sscanf(buf.String(), "%d", &n); err != nil { 184 | switch n { 185 | case 47: 186 | xy := coord{ 187 | y: csbi.window.top, 188 | x: csbi.window.left, 189 | } 190 | procSetConsoleCursorPosition.Call(uintptr(w.out), uintptr(*(*int32)(unsafe.Pointer(&xy)))) 191 | } 192 | } 193 | case '@': 194 | if _, err := fmt.Sscanf(buf.String(), "%d", &n); err != nil { 195 | n = 1 196 | } 197 | var ci charInfo 198 | ci.unicodeChar = ' ' 199 | ci.attributes = csbi.attributes 200 | var move smallRect 201 | move.top = csbi.cursorPosition.y 202 | move.bottom = move.top 203 | move.left = csbi.cursorPosition.x 204 | move.right = csbi.size.x - short(n) 205 | xy := coord{ 206 | x: csbi.cursorPosition.x + short(n), 207 | y: csbi.cursorPosition.y, 208 | } 209 | r1, _, _ = procScrollConsoleScreenBuffer.Call(uintptr(w.out), uintptr(unsafe.Pointer(&move)), 0, uintptr(*(*int32)(unsafe.Pointer(&xy))), uintptr(unsafe.Pointer(&ci))) 210 | if r1 == 0 { 211 | break 212 | } 213 | r1, _, _ = procSetConsoleCursorPosition.Call(uintptr(w.out), uintptr(*(*int32)(unsafe.Pointer(&csbi.cursorPosition)))) 214 | if r1 == 0 { 215 | break 216 | } 217 | case 'm': 218 | attr := csbi.attributes 219 | cs := buf.String() 220 | if cs == "" { 221 | procSetConsoleTextAttribute.Call(uintptr(w.out), uintptr(attr_old)) 222 | continue 223 | } 224 | for _, ns := range strings.Split(cs, ";") { 225 | if n, err = strconv.Atoi(ns); err == nil { 226 | switch { 227 | case n == 0 || n == 100: 228 | attr = attr_old 229 | case 1 <= n && n <= 5: 230 | attr |= foregroundIntensity 231 | case n == 7: 232 | attr = ((attr & foregroundMask) << 4) | ((attr & backgroundMask) >> 4) 233 | case 22 == n || n == 25 || n == 25: 234 | attr |= foregroundIntensity 235 | case n == 27: 236 | attr = ((attr & foregroundMask) << 4) | ((attr & backgroundMask) >> 4) 237 | case 30 <= n && n <= 37: 238 | attr = (attr & backgroundMask) 239 | if (n-30)&1 != 0 { 240 | attr |= foregroundRed 241 | } 242 | if (n-30)&2 != 0 { 243 | attr |= foregroundGreen 244 | } 245 | if (n-30)&4 != 0 { 246 | attr |= foregroundBlue 247 | } 248 | case 40 <= n && n <= 47: 249 | attr = (attr & foregroundMask) 250 | if (n-40)&1 != 0 { 251 | attr |= backgroundRed 252 | } 253 | if (n-40)&2 != 0 { 254 | attr |= backgroundGreen 255 | } 256 | if (n-40)&4 != 0 { 257 | attr |= backgroundBlue 258 | } 259 | } 260 | procSetConsoleTextAttribute.Call(uintptr(w.out), uintptr(attr)) 261 | } 262 | } 263 | case 'A': 264 | ns, _ := fmt.Sscanf(buf.String(), "%d", &n) 265 | if ns == 0 { 266 | csbi.cursorPosition.y-- 267 | } else { 268 | csbi.cursorPosition.y -= short(n) 269 | } 270 | r1, _, _ = procSetConsoleCursorPosition.Call(uintptr(w.out), uintptr(*(*int32)(unsafe.Pointer(&csbi.cursorPosition)))) 271 | if r1 == 0 { 272 | break 273 | } 274 | case 'B': 275 | ns, _ := fmt.Sscanf(buf.String(), "%d", &n) 276 | if ns == 0 { 277 | csbi.cursorPosition.y++ 278 | } else { 279 | csbi.cursorPosition.y += short(n) 280 | } 281 | r1, _, _ = procSetConsoleCursorPosition.Call(uintptr(w.out), uintptr(*(*int32)(unsafe.Pointer(&csbi.cursorPosition)))) 282 | if r1 == 0 { 283 | break 284 | } 285 | case 'C': 286 | ns, _ := fmt.Sscanf(buf.String(), "%d", &n) 287 | if ns == 0 { 288 | csbi.cursorPosition.x++ 289 | } else { 290 | csbi.cursorPosition.x += short(n) 291 | } 292 | r1, _, _ = procSetConsoleCursorPosition.Call(uintptr(w.out), uintptr(*(*int32)(unsafe.Pointer(&csbi.cursorPosition)))) 293 | if r1 == 0 { 294 | break 295 | } 296 | case 'D': 297 | ns, _ := fmt.Sscanf(buf.String(), "%d", &n) 298 | if ns == 0 { 299 | csbi.cursorPosition.x-- 300 | } else { 301 | csbi.cursorPosition.x -= short(n) 302 | } 303 | r1, _, _ = procSetConsoleCursorPosition.Call(uintptr(w.out), uintptr(*(*int32)(unsafe.Pointer(&csbi.cursorPosition)))) 304 | if r1 == 0 { 305 | break 306 | } 307 | case 'J': 308 | if _, err = fmt.Sscanf(buf.String(), "%d", &n); err != nil { 309 | n = 0 310 | } 311 | switch n { 312 | case 0: 313 | cursor := coord{ 314 | x: csbi.cursorPosition.x, 315 | y: csbi.cursorPosition.y, 316 | } 317 | var count, dw dword 318 | count = dword(csbi.size.x - csbi.cursorPosition.x + (csbi.size.y-csbi.cursorPosition.y)*csbi.size.x) 319 | r1, _, _ = procFillConsoleOutputCharacter.Call(uintptr(w.out), uintptr(' '), uintptr(count), *(*uintptr)(unsafe.Pointer(&cursor)), uintptr(unsafe.Pointer(&dw))) 320 | if r1 == 0 { 321 | break 322 | } 323 | r1, _, _ = procFillConsoleOutputAttribute.Call(uintptr(w.out), uintptr(csbi.attributes), uintptr(count), *(*uintptr)(unsafe.Pointer(&cursor)), uintptr(unsafe.Pointer(&dw))) 324 | if r1 == 0 { 325 | break 326 | } 327 | case 1: 328 | cursor := coord{ 329 | x: csbi.window.left, 330 | y: csbi.window.top, 331 | } 332 | var count, dw dword 333 | count = dword(csbi.cursorPosition.x + (csbi.cursorPosition.y-1)*csbi.size.x) 334 | r1, _, _ = procFillConsoleOutputCharacter.Call(uintptr(w.out), uintptr(' '), uintptr(count), *(*uintptr)(unsafe.Pointer(&cursor)), uintptr(unsafe.Pointer(&dw))) 335 | if r1 == 0 { 336 | break 337 | } 338 | r1, _, _ = procFillConsoleOutputAttribute.Call(uintptr(w.out), uintptr(csbi.attributes), uintptr(count), *(*uintptr)(unsafe.Pointer(&cursor)), uintptr(unsafe.Pointer(&dw))) 339 | if r1 == 0 { 340 | break 341 | } 342 | case 2: 343 | cursor := coord{ 344 | x: csbi.window.left, 345 | y: csbi.window.top, 346 | } 347 | var count, dw dword 348 | count = dword(csbi.size.x * csbi.size.y) 349 | r1, _, _ = procFillConsoleOutputCharacter.Call(uintptr(w.out), uintptr(' '), uintptr(count), *(*uintptr)(unsafe.Pointer(&cursor)), uintptr(unsafe.Pointer(&dw))) 350 | if r1 == 0 { 351 | break 352 | } 353 | r1, _, _ = procFillConsoleOutputAttribute.Call(uintptr(w.out), uintptr(csbi.attributes), uintptr(count), *(*uintptr)(unsafe.Pointer(&cursor)), uintptr(unsafe.Pointer(&dw))) 354 | if r1 == 0 { 355 | break 356 | } 357 | } 358 | case 'K': 359 | fmt.Sscanf(buf.String(), "%d", &n) 360 | switch n { 361 | case 0: 362 | cursor := coord{ 363 | x: csbi.cursorPosition.x, 364 | y: csbi.cursorPosition.y, 365 | } 366 | var count, dw dword 367 | count = dword(csbi.size.x - csbi.cursorPosition.x) 368 | r1, _, _ = procFillConsoleOutputCharacter.Call(uintptr(w.out), uintptr(' '), uintptr(count), *(*uintptr)(unsafe.Pointer(&cursor)), uintptr(unsafe.Pointer(&dw))) 369 | if r1 == 0 { 370 | break 371 | } 372 | r1, _, _ = procFillConsoleOutputAttribute.Call(uintptr(w.out), uintptr(csbi.attributes), uintptr(count), *(*uintptr)(unsafe.Pointer(&cursor)), uintptr(unsafe.Pointer(&dw))) 373 | if r1 == 0 { 374 | break 375 | } 376 | case 1: 377 | cursor := coord{ 378 | x: csbi.window.left, 379 | y: csbi.window.top + csbi.cursorPosition.y, 380 | } 381 | var count, dw dword 382 | count = dword(csbi.cursorPosition.x) 383 | r1, _, _ = procFillConsoleOutputCharacter.Call(uintptr(w.out), uintptr(' '), uintptr(count), *(*uintptr)(unsafe.Pointer(&cursor)), uintptr(unsafe.Pointer(&dw))) 384 | if r1 == 0 { 385 | break 386 | } 387 | r1, _, _ = procFillConsoleOutputAttribute.Call(uintptr(w.out), uintptr(csbi.attributes), uintptr(count), *(*uintptr)(unsafe.Pointer(&cursor)), uintptr(unsafe.Pointer(&dw))) 388 | if r1 == 0 { 389 | break 390 | } 391 | case 2: 392 | cursor := coord{ 393 | x: csbi.window.left, 394 | y: csbi.window.top + csbi.cursorPosition.y, 395 | } 396 | var count, dw dword 397 | count = dword(csbi.size.x) 398 | r1, _, _ = procFillConsoleOutputCharacter.Call(uintptr(w.out), uintptr(' '), uintptr(count), *(*uintptr)(unsafe.Pointer(&cursor)), uintptr(unsafe.Pointer(&dw))) 399 | if r1 == 0 { 400 | break 401 | } 402 | r1, _, _ = procFillConsoleOutputAttribute.Call(uintptr(w.out), uintptr(csbi.attributes), uintptr(count), *(*uintptr)(unsafe.Pointer(&cursor)), uintptr(unsafe.Pointer(&dw))) 403 | if r1 == 0 { 404 | break 405 | } 406 | } 407 | case 'H': 408 | var xy coord 409 | ns, _ := fmt.Sscanf(buf.String(), "%d;%d", &xy.y, &xy.x) 410 | if ns == 1 { 411 | xy.y-- 412 | } else if ns == 2 { 413 | xy.y-- 414 | xy.x-- 415 | } 416 | xy.y += csbi.window.top 417 | xy.x += csbi.window.left 418 | procSetConsoleCursorPosition.Call(uintptr(w.out), uintptr(*(*int32)(unsafe.Pointer(&xy)))) 419 | case 'r': 420 | scroll = &smallRect{} 421 | ns, _ := fmt.Sscanf(buf.String(), "%d;%d", &scroll.top, &scroll.left) 422 | scroll.left = csbi.window.left 423 | scroll.right = csbi.window.right 424 | if ns == 0 { 425 | scroll = nil 426 | } else if ns == 1 { 427 | scroll.top-- 428 | } else if ns == 2 { 429 | scroll.bottom-- 430 | } 431 | } 432 | } 433 | return len(b), nil 434 | } 435 | 436 | func init() { 437 | out = &WindowsConsoleWriter{syscall.Handle(os.Stdout.Fd())} 438 | } 439 | --------------------------------------------------------------------------------