Typestead
hello.pynotes.md
def greet(name):
    # say hi to a friend
    return f"Hi, {name}!"

for friend in ["Ana", "Sam"]:
    print(greet(friend))

Typestead: code in your pocket

A pocket-sized code and text editor for Android. 25 languages, works offline, and your files never leave your phone.

7 days free, then a single payment with no ads and no subscription.

Android 8.0 and up

Coming to Google Play

25 languages. Tap one.

Each one gets its own colours, completion, smart indent and Function List. Plus JSON, XML, HTML, CSS, YAML, Markdown and logs.

Python.py .pyw#Data

Indents after a colon. else:, elif: and except: step back on their own.

example.py
def average(marks):
    # empty list? say so
    if not marks:
        return 0
    return sum(marks) / len(marks)

print(average([72, 88, 95]))
PythonUTF-8 · LF
JavaScript.js .mjs//Web

Brackets and quotes close themselves, and typing the closer just steps over it.

example.js
const todo = ["read", "code", "sleep"];

function next(list) {
  // take the first job
  return list.shift() ?? "nothing left";
}
console.log(next(todo));
JavaScriptUTF-8 · LF
Java.java//Apps

Annotations get their own colour. Every class and method lands in the Function List.

example.java
public class Hello {
    @Override
    public String toString() {
        return "Hi from Java";
    }
    public static void main(String[] args) {
        System.out.println(new Hello());
    }
}
JavaUTF-8 · LF
C#.cs//Apps

Classes, methods and properties fill the Function List. Tap one to jump to it.

example.cs
public record Grade(string Name, int Score);

public static class Report
{
    // highest score wins
    public static Grade Top(List<Grade> all)
        => all.MaxBy(g => g.Score);
}
C#UTF-8 · LF
C++.cpp .hpp .cc//Systems

Preprocessor lines, raw strings and block comments are each coloured correctly.

example.cpp
#include <vector>
#include <iostream>

int main() {
    std::vector<int> v{3, 1, 2};
    /* print every item */
    for (auto x : v) std::cout << x << "\n";
    return 0;
}
C++UTF-8 · LF
TypeScript.ts .tsx//Web

Types and interfaces stand out; the Function List finds functions and classes.

example.ts
interface Task {
  title: string;
  done: boolean;
}

export function left(tasks: Task[]): number {
  return tasks.filter(t => !t.done).length;
}
TypeScriptUTF-8 · LF
SQL.sql--Data

Completion follows your case: type sel and get SELECT if that is how you write it.

example.sql
-- top students this term
SELECT name, AVG(score) AS avg_score
FROM results
WHERE term = 'T4'
GROUP BY name
ORDER BY avg_score DESC
LIMIT 5;
SQLUTF-8 · LF
C.c .h/* */Systems

Go to matching bracket ignores the brackets inside strings and comments.

example.c
#include <stdio.h>

int main(void) {
    int total = 0;
    for (int i = 1; i <= 10; i++)
        total += i;   /* 1 + 2 + ... + 10 */
    printf("%d\n", total);
    return 0;
}
CUTF-8 · LF
Go.go//Systems

Indents inside braces, and every func shows up in the Function List.

example.go
package main

import "fmt"

func double(n int) int {
	return n * 2
}

func main() {
	fmt.Println(double(21))
}
GoUTF-8 · LF
PHP.php//Web

Variables get their own colour, so a mistyped $name is easy to spot.

example.php
<?php
// greet each friend
$friends = ["Ana", "Sam"];
foreach ($friends as $name) {
    echo "Hi, $name!\n";
}
PHPUTF-8 · LF
Rust.rs//Systems

Lifetimes like 'a are never mistaken for an opening quote.

example.rs
fn longest<'a>(a: &'a str, b: &'a str) -> &'a str {
    // return the longer one
    if a.len() >= b.len() { a } else { b }
}

fn main() {
    println!("{}", longest("pocket", "editor"));
}
RustUTF-8 · LF
Kotlin.kt .kts//Apps

fun and class names fill the Function List; braces indent as you type.

example.kt
data class Note(val title: String, val words: Int)

fun longest(notes: List<Note>): Note? =
    notes.maxByOrNull { it.words }

fun main() {
    println(longest(listOf(Note("a", 3))))
}
KotlinUTF-8 · LF
Swift.swift//Apps

Multi-line strings stay one colour from the first quotes to the last.

example.swift
struct Timer {
    var seconds: Int
    func label() -> String {
        // 90 -> "1:30"
        return "\(seconds / 60):\(seconds % 60)"
    }
}
print(Timer(seconds: 90).label())
SwiftUTF-8 · LF
R.r .R#Data

Recognised from the .R extension or a #! line; comments, strings and numbers all coloured.

example.r
# marks from the last quiz
marks <- c(72, 88, 95, 61)

summary_stats <- function(x) {
  c(mean = mean(x), top = max(x))
}
print(summary_stats(marks))
RUTF-8 · LF
Ruby.rb#Scripts

=begin … =end blocks read as comments, and end steps back automatically.

example.rb
=begin
A tiny shopping list
=end
class List
  def initialize
    @items = []
  end
  def add(item) = @items << item
end
RubyUTF-8 · LF
Bash / Shell.sh .bash#Scripts

Spotted from #!/bin/bash. then and do indent; fi steps back by itself.

example.sh
#!/bin/bash
# back up every .md file
for f in *.md; do
  if [ -s "$f" ]; then
    cp "$f" "backup/$f"
  fi
done
Bash / ShellUTF-8 · LF
PowerShell.ps1 .psm1#Scripts

Here-strings are one string, top to bottom. Also detected from a #!pwsh line.

example.ps1
# list big files
$limit = 10MB
Get-ChildItem -Recurse | Where-Object {
    $_.Length -gt $limit
}
$note = @"
Done checking.
"@
PowerShellUTF-8 · LF
Dart.dart//Apps

Brackets and quotes close themselves; classes and functions fill the Function List.

example.dart
class Score {
  final String name;
  final int points;
  Score(this.name, this.points);
}

void main() {
  print(Score('Ana', 42).points);
}
DartUTF-8 · LF
Scala.scala .sc//Apps

def, class and object names fill the Function List.

example.scala
object Main {
  // sum of squares
  def squares(n: Int): Int =
    (1 to n).map(x => x * x).sum

  def main(args: Array[String]): Unit =
    println(squares(4))
}
ScalaUTF-8 · LF
MATLAB.m%Data

Knows a transpose (A') from the start of a string.

example.m
% rotate a small matrix
A = [1 2; 3 4];
B = A';
label = 'transposed';
disp(label)
disp(B)
MATLABUTF-8 · LF
Visual Basic / VBA.vb .bas .cls'Business

If … Then indents and End If steps back. A ' comment never opens a quote.

example.vb
' total a column in Excel
Sub AddUp()
    Dim total As Long
    For Each c In Range("A1:A10")
        If c.Value > 0 Then total = total + c.Value
    Next
    MsgBox total
End Sub
Visual Basic / VBAUTF-8 · LF
Perl.pl .pm#Scripts

POD blocks read as comments, and $scalars, @arrays and %hashes stand out.

example.pl
use strict;
my @words = qw(pocket code editor);

=pod
Print each word.
=cut

print "$_\n" foreach @words;
PerlUTF-8 · LF
Lua.lua--Scripts

then and do indent; end steps back automatically.

example.lua
-- count the vowels
local function vowels(s)
  local n = 0
  for c in s:gmatch("[aeiou]") do
    n = n + 1
  end
  return n
end
print(vowels("typestead"))
LuaUTF-8 · LF
ABAP.abap* "Business

Toggling a comment puts * in column 1, the way ABAP expects.

example.abap
* list open orders
REPORT zorders.
DATA lt_orders TYPE TABLE OF vbak.
SELECT * FROM vbak INTO TABLE lt_orders
  WHERE gbstk = 'A'.
LOOP AT lt_orders INTO DATA(ls_o).
  WRITE / ls_o-vbeln. " order number
ENDLOOP.
ABAPUTF-8 · LF
Assembly.asm .s;Systems

Registers and labels get their own colours; labels fill the Function List.

example.asm
section .text
global _start
_start:
    mov rax, 60      ; exit
    xor rdi, rdi     ; code 0
    syscall
AssemblyUTF-8 · LF

How a file travels

hello.py
def greet(name):
    return "Hi, " + name

print(greet("Ana"))
Opened from Files1.2 KB

First, open any file.

hello.py
def greet(name):
    return "Hi, " + name

print(greet("Ana"))
PythonUTF-8 · LF

Then Typestead reads it.

hello.py
def greet(name):
    return "Hi, " + name

for f in friends:
    pr

You write. It helps.

hello (1).py
def greet(name):
    return "Hi, " + name

for f in friends:
    print(greet(f))

Saved to saved/hello (1).py. Nothing was overwritten.

Save. Nothing gets overwritten.

7 days free.
Then pay once.

One Google Play purchase unlocks everything on up to two Android phones. No ads, no subscription, no locked extras.

Coming to Google PlayHow the trial works

Google Play shows the price in your own currency before you buy.

Fair questions

Still stuck? Ask us.

Do my files ever leave my phone?

No. Typestead only goes online to check your licence. File names and file contents are never sent anywhere.

It also asks for no storage permission: it can only open the files and folders you pick.

Does it work without internet?

Yes. Everything works offline. It needs a connection about once a week to refresh your licence; you get 7 days offline between checks.

What happens when the 7-day trial ends?

The editor locks until you buy. You can still buy, restore a purchase, sign out, and export any unsaved drafts, so text kept only inside the app is never trapped.

Your files are ordinary files on your phone; they stay where they are and open in any other app.

Is it a subscription?

No. One purchase through Google Play and it's yours. No ads, no subscription, no in-app upsells.

How many phones can I use it on?

Two Android devices per Google account. On a third, sign one out from the app, or choose Sign out everywhere and use here.

I lost my phone. Now what?

On your other device, open Settings and choose Sign out everywhere. That frees both slots.

Which phones does it run on?

Android 8.0 or newer. Plug in a keyboard and the shortcuts work too.

Why do I sign in with Google?

Only to tie your licence to you, not to a single phone. The server never stores your email address, only a scrambled code made from your account ID.

Can I delete my account?

Yes: in the app under Settings, Delete account. Without the app, use the deletion page linked at the bottom of this site.

Ready to write code?

Coming to Google PlayorRead the guide

Sign in with Google and every feature is yours for 7 days. Buy only if you love it.