Ensure errors are handled or logged
if err != nil {
1// Copyright 2009 The Go Authors. All rights reserved.2// Use of this source code is governed by a BSD-style3// license that can be found in the LICENSE file.45// Package bufio implements buffered I/O. It wraps an io.Reader or io.Writer6// object, creating another object (Reader or Writer) that also implements7// the interface but provides buffering and some help for textual I/O.8package bufio910import (11 "bytes"12 "errors"13 "io"14 "strings"15 "unicode/utf8"16)1718const (19 defaultBufSize = 409620)2122var (23 ErrInvalidUnreadByte = errors.New("bufio: invalid use of UnreadByte")24 ErrInvalidUnreadRune = errors.New("bufio: invalid use of UnreadRune")25 ErrBufferFull = errors.New("bufio: buffer full")26 ErrNegativeCount = errors.New("bufio: negative count")27)2829// Buffered input.3031// Reader implements buffering for an io.Reader object.32// A new Reader is created by calling [NewReader] or [NewReaderSize];33// alternatively the zero value of a Reader may be used after calling [Reader.Reset]34// on it.35type Reader struct {36 buf []byte37 rd io.Reader // reader provided by the client38 r, w int // buf read and write positions39 err error40 lastByte int // last byte read for UnreadByte; -1 means invalid41 lastRuneSize int // size of last rune read for UnreadRune; -1 means invalid42}4344const minReadBufferSize = 1645const maxConsecutiveEmptyReads = 1004647// NewReaderSize returns a new [Reader] whose buffer has at least the specified48// size. If the argument io.Reader is already a [Reader] with large enough49// size, it returns the underlying [Reader].50func NewReaderSize(rd io.Reader, size int) *Reader {51 // Is it already a Reader?52 b, ok := rd.(*Reader)53 if ok && len(b.buf) >= size {54 return b55 }56 r := new(Reader)57 r.reset(make([]byte, max(size, minReadBufferSize)), rd)58 return r59}6061// NewReader returns a new [Reader] whose buffer has the default size.62func NewReader(rd io.Reader) *Reader {63 return NewReaderSize(rd, defaultBufSize)64}6566// Size returns the size of the underlying buffer in bytes.67func (b *Reader) Size() int { return len(b.buf) }6869// Reset discards any buffered data, resets all state, and switches70// the buffered reader to read from r.71// Calling Reset on the zero value of [Reader] initializes the internal buffer72// to the default size.73// Calling b.Reset(b) (that is, resetting a [Reader] to itself) does nothing.74func (b *Reader) Reset(r io.Reader) {75 // If a Reader r is passed to NewReader, NewReader will return r.76 // Different layers of code may do that, and then later pass r77 // to Reset. Avoid infinite recursion in that case.78 if b == r {79 return80 }81 if b.buf == nil {82 b.buf = make([]byte, defaultBufSize)83 }84 b.reset(b.buf, r)85}8687func (b *Reader) reset(buf []byte, r io.Reader) {88 *b = Reader{89 buf: buf,90 rd: r,91 lastByte: -1,92 lastRuneSize: -1,93 }94}9596var errNegativeRead = errors.New("bufio: reader returned negative count from Read")9798// fill reads a new chunk into the buffer.99func (b *Reader) fill() {100 // Slide existing data to beginning.101 if b.r > 0 {102 copy(b.buf, b.buf[b.r:b.w])103 b.w -= b.r104 b.r = 0105 }106107 if b.w >= len(b.buf) {108 panic("bufio: tried to fill full buffer")109 }110111 // Read new data: try a limited number of times.112 for i := maxConsecutiveEmptyReads; i > 0; i-- {113 n, err := b.rd.Read(b.buf[b.w:])114 if n < 0 {115 panic(errNegativeRead)116 }117 b.w += n118 if err != nil {119 b.err = err120 return121 }122 if n > 0 {123 return124 }125 }126 b.err = io.ErrNoProgress127}128129func (b *Reader) readErr() error {130 err := b.err131 b.err = nil132 return err133}134135// Peek returns the next n bytes without advancing the reader. The bytes stop136// being valid at the next read call. If necessary, Peek will read more bytes137// into the buffer in order to make n bytes available. If Peek returns fewer138// than n bytes, it also returns an error explaining why the read is short.139// The error is [ErrBufferFull] if n is larger than b's buffer size.140//141// Calling Peek prevents a [Reader.UnreadByte] or [Reader.UnreadRune] call from succeeding142// until the next read operation.143func (b *Reader) Peek(n int) ([]byte, error) {144 if n < 0 {145 return nil, ErrNegativeCount146 }147148 b.lastByte = -1149 b.lastRuneSize = -1150151 for b.w-b.r < n && b.w-b.r < len(b.buf) && b.err == nil {152 b.fill() // b.w-b.r < len(b.buf) => buffer is not full153 }154155 if n > len(b.buf) {156 return b.buf[b.r:b.w], ErrBufferFull157 }158159 // 0 <= n <= len(b.buf)160 var err error161 if avail := b.w - b.r; avail < n {162 // not enough data in buffer163 n = avail164 err = b.readErr()165 if err == nil {166 err = ErrBufferFull167 }168 }169 return b.buf[b.r : b.r+n], err170}171172// Discard skips the next n bytes, returning the number of bytes discarded.173//174// If Discard skips fewer than n bytes, it also returns an error.175// If 0 <= n <= b.Buffered(), Discard is guaranteed to succeed without176// reading from the underlying io.Reader.177func (b *Reader) Discard(n int) (discarded int, err error) {178 if n < 0 {179 return 0, ErrNegativeCount180 }181 if n == 0 {182 return183 }184185 b.lastByte = -1186 b.lastRuneSize = -1187188 remain := n189 for {190 skip := b.Buffered()191 if skip == 0 {192 b.fill()193 skip = b.Buffered()194 }195 if skip > remain {196 skip = remain197 }198 b.r += skip199 remain -= skip200 if remain == 0 {201 return n, nil202 }203 if b.err != nil {204 return n - remain, b.readErr()205 }206 }207}208209// Read reads data into p.210// It returns the number of bytes read into p.211// The bytes are taken from at most one Read on the underlying [Reader],212// hence n may be less than len(p).213// To read exactly len(p) bytes, use io.ReadFull(b, p).214// If the underlying [Reader] can return a non-zero count with io.EOF,215// then this Read method can do so as well; see the [io.Reader] docs.216func (b *Reader) Read(p []byte) (n int, err error) {217 n = len(p)218 if n == 0 {219 if b.Buffered() > 0 {220 return 0, nil221 }222 return 0, b.readErr()223 }224 if b.r == b.w {225 if b.err != nil {226 return 0, b.readErr()227 }228 if len(p) >= len(b.buf) {229 // Large read, empty buffer.230 // Read directly into p to avoid copy.231 n, b.err = b.rd.Read(p)232 if n < 0 {233 panic(errNegativeRead)234 }235 if n > 0 {236 b.lastByte = int(p[n-1])237 b.lastRuneSize = -1238 }239 return n, b.readErr()240 }241 // One read.242 // Do not use b.fill, which will loop.243 b.r = 0244 b.w = 0245 n, b.err = b.rd.Read(b.buf)246 if n < 0 {247 panic(errNegativeRead)248 }249 if n == 0 {250 return 0, b.readErr()251 }252 b.w += n253 }254255 // copy as much as we can256 // Note: if the slice panics here, it is probably because257 // the underlying reader returned a bad count. See issue 49795.258 n = copy(p, b.buf[b.r:b.w])259 b.r += n260 b.lastByte = int(b.buf[b.r-1])261 b.lastRuneSize = -1262 return n, nil263}264265// ReadByte reads and returns a single byte.266// If no byte is available, returns an error.267func (b *Reader) ReadByte() (byte, error) {268 b.lastRuneSize = -1269 for b.r == b.w {270 if b.err != nil {271 return 0, b.readErr()272 }273 b.fill() // buffer is empty274 }275 c := b.buf[b.r]276 b.r++277 b.lastByte = int(c)278 return c, nil279}280281// UnreadByte unreads the last byte. Only the most recently read byte can be unread.282//283// UnreadByte returns an error if the most recent method called on the284// [Reader] was not a read operation. Notably, [Reader.Peek], [Reader.Discard], and [Reader.WriteTo] are not285// considered read operations.286func (b *Reader) UnreadByte() error {287 if b.lastByte < 0 || b.r == 0 && b.w > 0 {288 return ErrInvalidUnreadByte289 }290 // b.r > 0 || b.w == 0291 if b.r > 0 {292 b.r--293 } else {294 // b.r == 0 && b.w == 0295 b.w = 1296 }297 b.buf[b.r] = byte(b.lastByte)298 b.lastByte = -1299 b.lastRuneSize = -1300 return nil301}302303// ReadRune reads a single UTF-8 encoded Unicode character and returns the304// rune and its size in bytes. If the encoded rune is invalid, it consumes one byte305// and returns unicode.ReplacementChar (U+FFFD) with a size of 1.306func (b *Reader) ReadRune() (r rune, size int, err error) {307 for b.r+utf8.UTFMax > b.w && !utf8.FullRune(b.buf[b.r:b.w]) && b.err == nil && b.w-b.r < len(b.buf) {308 b.fill() // b.w-b.r < len(buf) => buffer is not full309 }310 b.lastRuneSize = -1311 if b.r == b.w {312 return 0, 0, b.readErr()313 }314 r, size = utf8.DecodeRune(b.buf[b.r:b.w])315 b.r += size316 b.lastByte = int(b.buf[b.r-1])317 b.lastRuneSize = size318 return r, size, nil319}320321// UnreadRune unreads the last rune. If the most recent method called on322// the [Reader] was not a [Reader.ReadRune], [Reader.UnreadRune] returns an error. (In this323// regard it is stricter than [Reader.UnreadByte], which will unread the last byte324// from any read operation.)325func (b *Reader) UnreadRune() error {326 if b.lastRuneSize < 0 || b.r < b.lastRuneSize {327 return ErrInvalidUnreadRune328 }329 b.r -= b.lastRuneSize330 b.lastByte = -1331 b.lastRuneSize = -1332 return nil333}334335// Buffered returns the number of bytes that can be read from the current buffer.336func (b *Reader) Buffered() int { return b.w - b.r }337338// ReadSlice reads until the first occurrence of delim in the input,339// returning a slice pointing at the bytes in the buffer.340// The bytes stop being valid at the next read.341// If ReadSlice encounters an error before finding a delimiter,342// it returns all the data in the buffer and the error itself (often io.EOF).343// ReadSlice fails with error [ErrBufferFull] if the buffer fills without a delim.344// Because the data returned from ReadSlice will be overwritten345// by the next I/O operation, most clients should use346// [Reader.ReadBytes] or ReadString instead.347// ReadSlice returns err != nil if and only if line does not end in delim.348func (b *Reader) ReadSlice(delim byte) (line []byte, err error) {349 s := 0 // search start index350 for {351 // Search buffer.352 if i := bytes.IndexByte(b.buf[b.r+s:b.w], delim); i >= 0 {353 i += s354 line = b.buf[b.r : b.r+i+1]355 b.r += i + 1356 break357 }358359 // Pending error?360 if b.err != nil {361 line = b.buf[b.r:b.w]362 b.r = b.w363 err = b.readErr()364 break365 }366367 // Buffer full?368 if b.Buffered() >= len(b.buf) {369 b.r = b.w370 line = b.buf371 err = ErrBufferFull372 break373 }374375 s = b.w - b.r // do not rescan area we scanned before376377 b.fill() // buffer is not full378 }379380 // Handle last byte, if any.381 if i := len(line) - 1; i >= 0 {382 b.lastByte = int(line[i])383 b.lastRuneSize = -1384 }385386 return387}388389// ReadLine is a low-level line-reading primitive. Most callers should use390// [Reader.ReadBytes]('\n') or [Reader.ReadString]('\n') instead or use a [Scanner].391//392// ReadLine tries to return a single line, not including the end-of-line bytes.393// If the line was too long for the buffer then isPrefix is set and the394// beginning of the line is returned. The rest of the line will be returned395// from future calls. isPrefix will be false when returning the last fragment396// of the line. The returned buffer is only valid until the next call to397// ReadLine. ReadLine either returns a non-nil line or it returns an error,398// never both.399//400// The text returned from ReadLine does not include the line end ("\r\n" or "\n").401// No indication or error is given if the input ends without a final line end.402// Calling [Reader.UnreadByte] after ReadLine will always unread the last byte read403// (possibly a character belonging to the line end) even if that byte is not404// part of the line returned by ReadLine.405func (b *Reader) ReadLine() (line []byte, isPrefix bool, err error) {406 line, err = b.ReadSlice('\n')407 if err == ErrBufferFull {408 // Handle the case where "\r\n" straddles the buffer.409 if len(line) > 0 && line[len(line)-1] == '\r' {410 // Put the '\r' back on buf and drop it from line.411 // Let the next call to ReadLine check for "\r\n".412 if b.r == 0 {413 // should be unreachable414 panic("bufio: tried to rewind past start of buffer")415 }416 b.r--417 line = line[:len(line)-1]418 }419 return line, true, nil420 }421422 if len(line) == 0 {423 if err != nil {424 line = nil425 }426 return427 }428 err = nil429430 if line[len(line)-1] == '\n' {431 drop := 1432 if len(line) > 1 && line[len(line)-2] == '\r' {433 drop = 2434 }435 line = line[:len(line)-drop]436 }437 return438}439440// collectFragments reads until the first occurrence of delim in the input. It441// returns (slice of full buffers, remaining bytes before delim, total number442// of bytes in the combined first two elements, error).443// The complete result is equal to444// `bytes.Join(append(fullBuffers, finalFragment), nil)`, which has a445// length of `totalLen`. The result is structured in this way to allow callers446// to minimize allocations and copies.447func (b *Reader) collectFragments(delim byte) (fullBuffers [][]byte, finalFragment []byte, totalLen int, err error) {448 var frag []byte449 // Use ReadSlice to look for delim, accumulating full buffers.450 for {451 var e error452 frag, e = b.ReadSlice(delim)453 if e == nil { // got final fragment454 break455 }456 if e != ErrBufferFull { // unexpected error457 err = e458 break459 }460461 // Make a copy of the buffer.462 buf := bytes.Clone(frag)463 fullBuffers = append(fullBuffers, buf)464 totalLen += len(buf)465 }466467 totalLen += len(frag)468 return fullBuffers, frag, totalLen, err469}470471// ReadBytes reads until the first occurrence of delim in the input,472// returning a slice containing the data up to and including the delimiter.473// If ReadBytes encounters an error before finding a delimiter,474// it returns the data read before the error and the error itself (often io.EOF).475// ReadBytes returns err != nil if and only if the returned data does not end in476// delim.477// For simple uses, a Scanner may be more convenient.478func (b *Reader) ReadBytes(delim byte) ([]byte, error) {479 full, frag, n, err := b.collectFragments(delim)480 // Allocate new buffer to hold the full pieces and the fragment.481 buf := make([]byte, n)482 n = 0483 // Copy full pieces and fragment in.484 for i := range full {485 n += copy(buf[n:], full[i])486 }487 copy(buf[n:], frag)488 return buf, err489}490491// ReadString reads until the first occurrence of delim in the input,492// returning a string containing the data up to and including the delimiter.493// If ReadString encounters an error before finding a delimiter,494// it returns the data read before the error and the error itself (often io.EOF).495// ReadString returns err != nil if and only if the returned data does not end in496// delim.497// For simple uses, a Scanner may be more convenient.498func (b *Reader) ReadString(delim byte) (string, error) {499 full, frag, n, err := b.collectFragments(delim)500 // Allocate new buffer to hold the full pieces and the fragment.501 var buf strings.Builder502 buf.Grow(n)503 // Copy full pieces and fragment in.504 for _, fb := range full {505 buf.Write(fb)506 }507 buf.Write(frag)508 return buf.String(), err509}510511// WriteTo implements io.WriterTo.512// This may make multiple calls to the [Reader.Read] method of the underlying [Reader].513// If the underlying reader supports the [Reader.WriteTo] method,514// this calls the underlying [Reader.WriteTo] without buffering.515func (b *Reader) WriteTo(w io.Writer) (n int64, err error) {516 b.lastByte = -1517 b.lastRuneSize = -1518519 if b.r < b.w {520 n, err = b.writeBuf(w)521 if err != nil {522 return523 }524 }525526 if r, ok := b.rd.(io.WriterTo); ok {527 m, err := r.WriteTo(w)528 n += m529 return n, err530 }531532 if w, ok := w.(io.ReaderFrom); ok {533 m, err := w.ReadFrom(b.rd)534 n += m535 return n, err536 }537538 if b.w-b.r < len(b.buf) {539 b.fill() // buffer not full540 }541542 for b.r < b.w {543 // b.r < b.w => buffer is not empty544 m, err := b.writeBuf(w)545 n += m546 if err != nil {547 return n, err548 }549 b.fill() // buffer is empty550 }551552 if b.err == io.EOF {553 b.err = nil554 }555556 return n, b.readErr()557}558559var errNegativeWrite = errors.New("bufio: writer returned negative count from Write")560561// writeBuf writes the [Reader]'s buffer to the writer.562func (b *Reader) writeBuf(w io.Writer) (int64, error) {563 n, err := w.Write(b.buf[b.r:b.w])564 if n < 0 {565 panic(errNegativeWrite)566 }567 b.r += n568 return int64(n), err569}570571// buffered output572573// Writer implements buffering for an [io.Writer] object.574// If an error occurs writing to a [Writer], no more data will be575// accepted and all subsequent writes, and [Writer.Flush], will return the error.576// After all data has been written, the client should call the577// [Writer.Flush] method to guarantee all data has been forwarded to578// the underlying [io.Writer].579type Writer struct {580 err error581 buf []byte582 n int583 wr io.Writer584}585586// NewWriterSize returns a new [Writer] whose buffer has at least the specified587// size. If the argument io.Writer is already a [Writer] with large enough588// size, it returns the underlying [Writer].589func NewWriterSize(w io.Writer, size int) *Writer {590 // Is it already a Writer?591 b, ok := w.(*Writer)592 if ok && len(b.buf) >= size {593 return b594 }595 if size <= 0 {596 size = defaultBufSize597 }598 return &Writer{599 buf: make([]byte, size),600 wr: w,601 }602}603604// NewWriter returns a new [Writer] whose buffer has the default size.605// If the argument io.Writer is already a [Writer] with large enough buffer size,606// it returns the underlying [Writer].607func NewWriter(w io.Writer) *Writer {608 return NewWriterSize(w, defaultBufSize)609}610611// Size returns the size of the underlying buffer in bytes.612func (b *Writer) Size() int { return len(b.buf) }613614// Reset discards any unflushed buffered data, clears any error, and615// resets b to write its output to w.616// Calling Reset on the zero value of [Writer] initializes the internal buffer617// to the default size.618// Calling w.Reset(w) (that is, resetting a [Writer] to itself) does nothing.619func (b *Writer) Reset(w io.Writer) {620 // If a Writer w is passed to NewWriter, NewWriter will return w.621 // Different layers of code may do that, and then later pass w622 // to Reset. Avoid infinite recursion in that case.623 if b == w {624 return625 }626 if b.buf == nil {627 b.buf = make([]byte, defaultBufSize)628 }629 b.err = nil630 b.n = 0631 b.wr = w632}633634// Flush writes any buffered data to the underlying [io.Writer].635func (b *Writer) Flush() error {636 if b.err != nil {637 return b.err638 }639 if b.n == 0 {640 return nil641 }642 n, err := b.wr.Write(b.buf[0:b.n])643 if n < b.n && err == nil {644 err = io.ErrShortWrite645 }646 if err != nil {647 if n > 0 && n < b.n {648 copy(b.buf[0:b.n-n], b.buf[n:b.n])649 }650 b.n -= n651 b.err = err652 return err653 }654 b.n = 0655 return nil656}657658// Available returns how many bytes are unused in the buffer.659func (b *Writer) Available() int { return len(b.buf) - b.n }660661// AvailableBuffer returns an empty buffer with b.Available() capacity.662// This buffer is intended to be appended to and663// passed to an immediately succeeding [Writer.Write] call.664// The buffer is only valid until the next write operation on b.665func (b *Writer) AvailableBuffer() []byte {666 return b.buf[b.n:][:0]667}668669// Buffered returns the number of bytes that have been written into the current buffer.670func (b *Writer) Buffered() int { return b.n }671672// Write writes the contents of p into the buffer.673// It returns the number of bytes written.674// If nn < len(p), it also returns an error explaining675// why the write is short.676func (b *Writer) Write(p []byte) (nn int, err error) {677 for len(p) > b.Available() && b.err == nil {678 var n int679 if b.Buffered() == 0 {680 // Large write, empty buffer.681 // Write directly from p to avoid copy.682 n, b.err = b.wr.Write(p)683 } else {684 n = copy(b.buf[b.n:], p)685 b.n += n686 b.Flush()687 }688 nn += n689 p = p[n:]690 }691 if b.err != nil {692 return nn, b.err693 }694 n := copy(b.buf[b.n:], p)695 b.n += n696 nn += n697 return nn, nil698}699700// WriteByte writes a single byte.701func (b *Writer) WriteByte(c byte) error {702 if b.err != nil {703 return b.err704 }705 if b.Available() <= 0 && b.Flush() != nil {706 return b.err707 }708 b.buf[b.n] = c709 b.n++710 return nil711}712713// WriteRune writes a single Unicode code point, returning714// the number of bytes written and any error.715func (b *Writer) WriteRune(r rune) (size int, err error) {716 // Compare as uint32 to correctly handle negative runes.717 if uint32(r) < utf8.RuneSelf {718 err = b.WriteByte(byte(r))719 if err != nil {720 return 0, err721 }722 return 1, nil723 }724 if b.err != nil {725 return 0, b.err726 }727 n := b.Available()728 if n < utf8.UTFMax {729 if b.Flush(); b.err != nil {730 return 0, b.err731 }732 n = b.Available()733 if n < utf8.UTFMax {734 // Can only happen if buffer is silly small.735 return b.WriteString(string(r))736 }737 }738 size = utf8.EncodeRune(b.buf[b.n:], r)739 b.n += size740 return size, nil741}742743// WriteString writes a string.744// It returns the number of bytes written.745// If the count is less than len(s), it also returns an error explaining746// why the write is short.747func (b *Writer) WriteString(s string) (int, error) {748 var sw io.StringWriter749 tryStringWriter := true750751 nn := 0752 for len(s) > b.Available() && b.err == nil {753 var n int754 if b.Buffered() == 0 && sw == nil && tryStringWriter {755 // Check at most once whether b.wr is a StringWriter.756 sw, tryStringWriter = b.wr.(io.StringWriter)757 }758 if b.Buffered() == 0 && tryStringWriter {759 // Large write, empty buffer, and the underlying writer supports760 // WriteString: forward the write to the underlying StringWriter.761 // This avoids an extra copy.762 n, b.err = sw.WriteString(s)763 } else {764 n = copy(b.buf[b.n:], s)765 b.n += n766 b.Flush()767 }768 nn += n769 s = s[n:]770 }771 if b.err != nil {772 return nn, b.err773 }774 n := copy(b.buf[b.n:], s)775 b.n += n776 nn += n777 return nn, nil778}779780// ReadFrom implements [io.ReaderFrom]. If the underlying writer781// supports the ReadFrom method, this calls the underlying ReadFrom.782// If there is buffered data and an underlying ReadFrom, this fills783// the buffer and writes it before calling ReadFrom.784func (b *Writer) ReadFrom(r io.Reader) (n int64, err error) {785 if b.err != nil {786 return 0, b.err787 }788 readerFrom, readerFromOK := b.wr.(io.ReaderFrom)789 var m int790 for {791 if b.Available() == 0 {792 if err1 := b.Flush(); err1 != nil {793 return n, err1794 }795 }796 if readerFromOK && b.Buffered() == 0 {797 nn, err := readerFrom.ReadFrom(r)798 b.err = err799 n += nn800 return n, err801 }802 nr := 0803 for nr < maxConsecutiveEmptyReads {804 m, err = r.Read(b.buf[b.n:])805 if m != 0 || err != nil {806 break807 }808 nr++809 }810 if nr == maxConsecutiveEmptyReads {811 return n, io.ErrNoProgress812 }813 b.n += m814 n += int64(m)815 if err != nil {816 break817 }818 }819 if err == io.EOF {820 // If we filled the buffer exactly, flush preemptively.821 if b.Available() == 0 {822 err = b.Flush()823 } else {824 err = nil825 }826 }827 return n, err828}829830// buffered input and output831832// ReadWriter stores pointers to a [Reader] and a [Writer].833// It implements [io.ReadWriter].834type ReadWriter struct {835 *Reader836 *Writer837}838839// NewReadWriter allocates a new [ReadWriter] that dispatches to r and w.840func NewReadWriter(r *Reader, w *Writer) *ReadWriter {841 return &ReadWriter{r, w}842}
Same data, no extra tab — call code_get_file + code_get_findings over MCP from Claude/Cursor/Copilot.