VS Code Extensions
Quick Print C/C++ C# JS/TS Java Go Rust

Quick Print C/C++ C# JS/TS Java Go Rust

by yassine123213

Select a variable, press a shortcut, get a printf debug line for C/C++.

Downloads

13

Rating

5.0 / 5 (1)

Version

0.0.6

Last updated

Aug 14, 2026

Select a variable (or just put your cursor in/on it), press Ctrl+Shift+L (Cmd+Shift+L on Mac), and get a debug line inserted right below — in whatever language you're editing.

int count = 0;

→

int count = 0;
printf("count = %d\n", count);
count = 0

→

count = 0
print(f"{count=}")
let count = 0;

→

let count = 0;
console.log('count =', count);

Supported languages

C / C++ get the full treatment: real type resolution (scans the file for the variable's declaration), correct printf format specifiers, indexed access (arr[2]), struct/pointer member access (obj.field, ptr->field), out-of-bounds warnings, and a for-loop mode for whole arrays. See the details below.

Everything else — Python, JavaScript/TypeScript (+ JSX/TSX), Java, Go, Rust, C#, PHP, Ruby, Swift, Kotlin, shell scripts, Lua — gets the correct idiomatic debug-print line for that language. No type resolution is needed there because these languages already auto-format any value (f-strings, %v, {:?}, string interpolation, etc.), so the extension just picks the right print/log call:

Language Generated line
Python print(f"{count=}")
JS/TS console.log('count =', count);
Java System.out.println("count = " + count);
Go fmt.Printf("count = %v\n", count)
Rust println!("count = {:?}", count);
C# Console.WriteLine($"count = {count}");
PHP error_log("count = " . print_r(count, true));
Ruby puts "count = #{count}"
Swift print("count = \(count)")
Kotlin println("count = $count")
Shell echo "count = $count"
Lua print("count = " .. tostring(count))

Language is detected from the file's VS Code language mode (editor.document.languageId), not the file extension, so it works in any file VS Code recognizes. If your language isn't in the table, it inserts a // TODO print debug: ... placeholder and shows a warning — open an issue / edit GENERIC_LANGUAGES in extension.js to add it (it's a one-line template function).

C/C++ details

It guesses the correct format specifier by scanning the file for the variable's declaration: %c/%d/%u for char variants, %hd/%hu for short, %ld/%lu for long, %lld/%llu for long long, %f for float/double, %zu/%zd for size_t/ssize_t, correct widths for the int8_t...uint64_t family, %s for char *, and %p for any other pointer. Falls back to %d if no declaration is found.

Indexed access (arr[2]) and struct member access (obj.field, ptr->field) are handled — the extension resolves the real element/field type rather than defaulting to %d. If a constant index is out of bounds for a known array size, you'll get a warning popup instead of a silently broken printf.

Whole-array printing: select just the array name (e.g. arr, no brackets) and it generates a for loop that prints every element instead of a single line:

int arr[5] = {1, 2, 3, 4, 5};
for (size_t __i_arr = 0; __i_arr < 5; __i_arr++)
	printf("arr[%zu] = %d\n", __i_arr, arr[__i_arr]);

Struct dump: select a bare variable whose type is a struct/aggregate and it prints every field instead of refusing. Scalar fields get a direct printf line; a pointer field that points to another known struct type and has a sibling size/count/len/capacity field is treated as a dynamic array and expanded into a for loop over its elements' fields; nested structs held by value are flattened recursively. Given:

typedef struct s_heap_node { long long key; int id; } t_heap_node;
typedef struct s_heap { t_heap_node *data; int size; int capacity; } t_heap;

t_heap *heap = ...;

selecting heap generates:

for (size_t __i0_data = 0; __i0_data < (size_t)heap->size; __i0_data++)
{
	printf("heap->data[%zu].key = %lld\n", __i0_data, heap->data[__i0_data].key);
	printf("heap->data[%zu].id = %d\n", __i0_data, heap->data[__i0_data].id);
}
printf("heap->size = %d\n", heap->size);
printf("heap->capacity = %d\n", heap->capacity);

It picks size over capacity as the loop bound when both exist, since that's usually "elements in use" rather than "slots allocated" — rename your fields to match if you want a different one picked, or just edit the generated loop condition afterward.

How to install (no publishing needed)

  1. Install the packaging tool once:
    npm install -g @vscode/vsce
    
  2. From this folder, package it:
    vsce package
    
    This produces printf-debug-0.0.1.vsix.
  3. In VS Code: Extensions view → ... menu (top right) → "Install from VSIX..." → select that file.

Reload VS Code and the shortcut is live in any file.

Changing the shortcut

Edit the keybindings section in package.json, e.g. change "key": "ctrl+Shift+l" to whatever you prefer, then repackage.

Notes / limitations

  • Type detection is a lightweight regex scan, not a real C parser.
  • Struct field resolution handles struct Tag { ... }; and typedef struct { ... } Alias; forms, one level deep — e.g. p.x or ptr->x. Chains like a.b.c or a->b->c only resolve the last field against a's type and will fall back to %d if that lookup fails. A warning popup tells you when this happens.
  • Whole-array loop mode only triggers when you select the bare array name with no index or brackets.
  • Struct dump: array-of-struct detection only fires when the pointer field's type is a struct known from this file and a sibling size/count/len/capacity field exists; otherwise it just prints the pointer address. Self-referential types (e.g. a linked-list next pointer to the same struct) are detected and skipped with a comment to avoid infinite recursion; nesting deeper than 4 levels is also cut off.
  • All %p args get an explicit (void *) cast, and all %lld/%llu args get an explicit (long long)/(unsigned long long) cast — this keeps output warning-free under -Wformat even for int64_t/uint64_t, whose underlying type differs by platform (long on Linux/macOS x86-64 and ARM64, long long elsewhere).
  • Works for both .c and .cpp files (no language restriction).

Related extensions