import re


def count_lines_with_wrapping(s, linewidth=80):
    """Count the number of lines in a given string.

    Lines are counted as if the string was wrapped so that lines are never over
    linewidth characters long.

    Tabs are considered tabwidth characters long.
    """
    tabwidth = 8  # Currently always true in Shell.
    pos = 0
    linecount = 1
    current_column = 0

    for m in re.finditer(r"[\t\n]", s):
        # Process the normal chars up to tab or newline.
        numchars = m.start() - pos
        pos += numchars
        current_column += numchars

        # Deal with tab or newline.
        if s[pos] == '\n':
            # Avoid the `current_column == 0` edge-case, and while we're
            # at it, don't bother adding 0.
            if current_column > linewidth:
                # If the current column was exactly linewidth, divmod
                # would give (1,0), even though a new line hadn't yet
                # been started. The same is true if length is any exact
                # multiple of linewidth. Therefore, subtract 1 before
                # dividing a non-empty line.
                linecount += (current_column - 1) // linewidth
            linecount += 1
            current_column = 0
        else:
            assert s[pos] == '\t'
            current_column += tabwidth - (current_column % tabwidth)

            # If a tab passes the end of the line, consider the entire
            # tab as being on the next line.
            if current_column > linewidth:
                linecount += 1
                current_column = tabwidth

        pos += 1 # After the tab or newline.

    # Process remaining chars (no more tabs or newlines).
    current_column += len(s) - pos
    # Avoid divmod(-1, linewidth).
    if current_column > 0:
        linecount += (current_column - 1) // linewidth
    else:
        # Text ended with newline; don't count an extra line after it.
        linecount -= 1

    return linecount