ForHosting KIT · Text & AI

Normalize text indentation levels

Lines indented by 2, 4 and 6 spaces are read as levels 1, 2 and 3 of a 2-space unit, and every line is rewritten to match that unit exactly. What follows the indent is never touched. Free in your browser.

  • Free
  • Runs in your browser
  • No sign-up
  • Your data stays on your device
Use it from WebAPIEmailTelegramApp soon
If you enter
Text
def foo(): if True: bar() baz() return
You get
Input
def foo(): if True: bar() baz() return
Indent style
spaces
Indent unit
2
Detected unit
2

Inconsistent leading whitespace is one of the most common paste-time headaches in code reviews, config dumps, and documentation blocks. A snippet may mix two-space and four-space steps, or worse, tabs on some lines and spaces on others, until a linter or a teammate rejects the file. This text indentation normalizer accepts multi-line plain text, classifies every non-blank line by how its leading indent is written, detects a single base unit—greatest common divisor of space counts, or one tab—and rewrites each line so the indent is an exact multiple of that unit.

How base indent detection and level rewriting work

The algorithm first normalizes Windows CRLF and legacy CR endings to a single LF form, then splits the document into lines. Fully blank lines stay blank and contribute no indent style. For every non-blank line the leading run of spaces and tabs is measured: if both characters appear in that leading run, or if other Unicode whitespace appears there, the line is treated as mixed and the whole request fails with a clear message naming the line number.

If some non-blank lines are space-indented and others are tab-indented, the document has no single clear style and is also rejected—conversion must be deliberate, not guessed. When every indented line uses spaces, the base unit is the greatest common divisor of all positive leading-space counts; if nothing is indented the default unit is two spaces for reporting. When every indented line uses tabs, the base unit is one tab and each leading tab counts as one level.

Each line’s level is then recomputed as count divided by unit (exact for the GCD of observed space counts, integer tab counts for tabs), and the line is rewritten with a pure prefix of either repeated spaces of length level times output unit, or repeated tabs of length level. Content after the leading indent is never altered: interior spaces, trailing spaces, and code tokens stay byte-identical.

Clean pasted code and config before commit

Developers paste snippets with mixed two- and four-space steps; the tool rewrites every line to one base unit and reports max indent depth for review.

How does the tool choose the base indentation unit?

For space-indented lines it uses the greatest common divisor of all positive leading-space counts (default reporting unit two when nothing is indented). For tab-indented lines the unit is one tab per level.

What happens if some lines use tabs and others use spaces?

A document-level mix of tabs and spaces has no clear single pattern; convert to one style first, then normalize.

Can I convert two-space indent to four-space indent?

Detected levels are preserved and each level is rewritten with four spaces.

Does normalization change code inside a line?

No. Only the leading indent run is rewritten. Interior spacing, trailing spaces, and all non-indent characters are left unchanged.

What happens to blank lines and Windows line breaks?

Fully blank lines stay blank and do not count when the indent style is detected. Windows and older line-break styles are converted to one standard line break before the lines are measured, so they never cause a mismatch.

Everything on this page is available programmatically. This section is for teams who want to wire it into their own systems; everyone else can just use the tool above.

POSThttps://api.kit.forhosting.com/text/text-indentation-normalize

Prefer to automate it? One authenticated POST creates the task; the result comes back by webhook or a signed link. The same capability also runs here on the web, by email and from Telegram — and soon from our app too.

curl -X POST https://api.kit.forhosting.com/text/text-indentation-normalize \
  -H "Authorization: Bearer $KIT_KEY" \
  -H "Content-Type: application/json" \
  -d '{"text":"def foo():\n  if True:\n      bar()\n    baz()"}'
{
  "text": "def foo():\n  if True:\n      bar()\n    baz()"
}
{
  "task_id": "tsk_a1b2c3d4e5f6a1b2c3d4e5f6",
  "type": "text.text_indentation_normalize",
  "status": "queued",
  "_links": {
    "result": "/tasks/tsk_…/result"
  }
}

The API is asynchronous: the call returns a task_id immediately and the result arrives by webhook. Polling is capped at 1 req/s per task.

Per request$0.002

Published price — no tokens, no invented credits. A failed task is never charged.

max_tokens20000
HTTPCodeMeaning
401unauthorizedMissing or invalid API key.
402insufficient_balanceYour balance doesn't cover the task price.
404unknown_typeThat task type doesn't exist.
429rate_limitedToo many requests. Use the webhook instead of polling.

When the same line or the document as a whole mixes tabs and spaces with no clear pattern, the task fails with invalid_input instead of silently guessing. Optional target_unit lets you re-scale space-based levels (for example from two spaces to four) without changing the logical depth tree.

How base indent detection and level rewriting work

Optional target_unit applies only to space-style documents: levels are preserved and the output uses that many spaces per level, which is how you convert a two-space tree into a four-space tree in one call. Tab-style input ignores target_unit so tabs are not silently expanded.

Input contract, response fields, and error behaviour

Prefer sending the raw multi-line body rather than pre-collapsing newlines when you want true per-line indent semantics; a single long line has only one indent to normalize. POST a JSON body with a required string field text (aliases input, value, string, s, content, and body). The value must be a non-empty string after overall whitespace trim and must not exceed one hundred thousand characters so a single paste cannot exhaust Worker or browser memory. Optional target_unit is a positive integer from one through thirty-two; non-integers and out-of-range values fail validation. On success the response echoes input as the original string, text as the fully rewritten multi-line result joined with LF, indent_style as spaces, tabs, or none, indent_unit as the effective output unit size, detected_unit as the unit inferred before any target override, line_count as the number of lines including blanks, indented_lines as how many lines had a positive level, max_level as the deepest indent level, levels as the per-line integer depth array aligned with lines, lines as the ordered array of rewritten line strings, and message as a short English summary of style, unit, line count, and max level. Failed validation—missing text, non-string values, empty content, oversize payload, invalid target_unit, same-line tab/space mix, or document-level style mix—returns invalid_input and is never charged. Pricing is a flat $0.002 per successful request with unit item. When integrating, assert on text or lines for the cleaned content, optionally compare levels and indent_unit for regression checks, and treat invalid_input as a client-side style conflict for mixed pastes rather than a billing event.

When to use this tool and how it differs from related searches

Use this capability when the search intent is normalize text indentation levels, fix inconsistent indent online, convert ragged two-and-four space paste to a single unit, or detect tab versus space indent style before a commit. Keep trailing whitespace and interior alignment columns in mind—this tool only rewrites the leading indent run, not alignment spaces inside a line. It is not a full code formatter, not a language-aware pretty printer, not a blank-line deleter, and not a global String.trim that would destroy intentional structure. Round-trip checks for tests are easy: feed a three-line block with zero, two, and four leading spaces and expect indent_unit two with levels zero, one, and two; feed pure tab-indented nested blocks and expect indent_style tabs with integer levels matching tab counts; deliberately send a line that begins with a tab then spaces, or one tab-indented line next to a space-indented sibling, and confirm invalid_input mentioning mix of tabs and spaces. Prefer str.trim_lines when you only need to strip leading and trailing whitespace from every line without preserving a depth tree; prefer data.json_format when the payload is JSON that should be pretty-printed with a fixed indent; prefer this capability when humans already wrote hierarchical plain text or code-like blocks and you need one consistent base unit. Failed tasks that return invalid_input do not consume prepaid balance, which keeps form validation and CI negative tests cheap.

CI and linter preprocessors

Pipelines reject mixed tabs and spaces early with invalid_input, or normalize space-only trees to a project target_unit before style checks run.

Docs, tutorials, and homework fixtures

Authors and teachers generate known-good indented multi-line examples and mixed-style error cases for editors, LMS tools, and golden tests.

What does normalize text indentation cost?

The browser tool is free. API requests use prepaid KIT balance at $0.002 per successful call; invalid input is not billed.

Read the full KIT documentation →