https://torchlight.dev
Torchlight - the API for Syntax Highlighting
Torchlight - the API for Syntax Highlighting Log In Pricing Docs Syntax highlighting is broken. Take a look at this example, from the configuration file of Laravel Octane. Most of the classes are completely unstyled! return [ 'listeners' => [ WorkerStarting::class => [ ❌ EnsureUploadedFilesAreValid::class, ❌ ], RequestReceived::class => [ ❌ ...Octane::prepareApplicationForNextOperation(), ❌ ...Octane::prepareApplicationForNextRequest(), ❌ ], WorkerErrorOccurred::class => [ ❌ ReportException::class, ❌ StopWorkerIfNecessary::class, ❌ ], ], 'warm' => [ ...Octane::defaultServicesToWarm(), ❌ ], ] Wrong Blade templates are completely wrong. Take a look at the last couple of lines. What's going on there? @if (count($records) === 1) ❌ I have one record! @elseif (count($records) > 1) ❌ I have {{ count($records) }} records! ❌ @else I don't have
any records! ❌ @endif ❌ Wrong It misses most of this JavaScript content as well. fs.readdirSync(path.join(process.cwd(), 'posts')).forEach(slug => { ❌ let content = fs.readFileSync( ❌ path.join(process.cwd(), 'posts', slug), ❌ 'utf-8' ) fs.writeFileSync( ❌ path.join(process.cwd(), 'build', `${slug}.html`), ❌ md.render(content) ❌ ) ❌ }) ❌ Wrong Torchlight is an API for syntax highlighting. Powered by the VS Code engine, focused on the joy of authoring. It always gets it right, even for esoteric stuff. Use any available VS Code theme, or make your own. It supports every language VS Code supports, and any language you can find a tmLanguage.json file for. It requires no JavaScript. Really. Torchlight is an HTTP API with server-side clients. Fully highlighted HTML is sent to the browser. No FOUC. Let's take a look at those examples again. Highlight.js misses all the classes here. return [ 'listeners' => [ WorkerStarting::class => [ ❌ EnsureUploadedFilesAreValid::class, ❌ ], RequestReceived::class => [ ❌ ...Octane::prepareApplicationForNextOperation(), ❌ ...Octane::prepareApplicationForNextRequest(), ❌ ], WorkerErrorOccurred::class => [ ❌ ReportException::class, ❌ StopWorkerIfNecessary::class, ❌ ], ], 'warm' => [ ...Octane::defaultServicesToWarm(), ❌ ], ] Torchlight correctly renders them all. 1return [ 2 'listeners' => [ 3 WorkerStarting::class => [ ✅ 4 EnsureUploadedFilesAreValid::class, ✅ 5 ], 6 7 RequestReceived::class => [ ✅ 8 ...Octane::prepareApplicationForNextOperation(), ✅ 9 ...Octane::prepareApplicationForNextRequest(), ✅10 ],11 12 WorkerErrorOccurred::class => [ ✅13 ReportException::class, ✅14 StopWorkerIfNecessary::class, ✅15 ],16 ],17 18 'warm' => [19 ...Octane::defaultServicesToWarm(), ✅20 ],21] Highlight.js doesn't support Blade at all. @if (count($records) === 1) ❌ I have one record! @elseif (count($records) > 1) ❌ I have {{ count($records) }} records! ❌ @else I don't have
any records! ❌ @endif ❌ Torchlight gets the Blade, PHP, and HTML right. 1@if (count($records) === 1) ✅2 I have one record!3@elseif (count($records) > 1) ✅4 I have {{ count($records) }} records! ✅5@else6 I don't have
any records! ✅7@endif ✅ Highlight.js doesn't correctly pick up the JavaScript methods fs.readdirSync(path.join(process.cwd(), 'posts')).forEach(slug => { ❌ let content = fs.readFileSync( ❌ path.join(process.cwd(), 'posts', slug), ❌ 'utf-8' ) fs.writeFileSync( ❌ path.join(process.cwd(), 'build', `${slug}.html`), ❌ md.render(content) ❌ ) ❌ }) ❌ Torchlight correctly picks them all up. 1fs.readdirSync(path.join(process.cwd(), 'posts')).forEach(slug => { ✅ 2 let content = fs.readFileSync( ✅ 3 path.join(process.cwd(), 'posts', slug), ✅ 4 'utf-8' 5 ) 6 7 fs.writeFileSync( ✅ 8 path.join(process.cwd(), 'build', `${slug}.html`), ✅ 9 md.render(content) ✅10 ) ✅11}) ✅ Getting the highlighting right is table-stakes. Torchlight focuses on the author experiences by helping you communicate your ideas clearly. You can control the display of your code using comments in your code. Using actual comments means no more messed up indentation or squiggly underlines in your editor. No more indecipherable syntaxes to remember to put at the top of your file. Annotate with inline comments. Let's look at some annotations. Focus Your Reader's Attention Quickly focus your reader's attention on the relevant portions of your code, while still giving the full context. Hover over the block to bring the whole block into focus. No JavaScript required! Just plain ol' CSS. Take a look at the source tab to see how it's done using Torchlight's focus annotation. Language: PHP Theme: Github Dark Result Source 1items, $size, true) as $chunk) { 17 $chunks[] = new static($chunk); 18 } 19 20 return new static($chunks);21} items, $size, true) as $chunk) { // [tl! **] $chunks[] = new static($chunk); // [tl! **] } // [tl! **] return new static($chunks); } Language: PHP. Theme: Github Dark Clearly Visualize Differences Diffs When explaining something in your docs or your blog posts, it's helpful to show your reader exactly what has changed. Take a look at the source tab to see how it's done using Torchlight's diff annotation. Language: PHP Theme: Github Dark Result Source 1items, $size, true) as $chunk) {18 $chunks[] = new static($chunk);19 }20 21 return new static($chunks);22} items, $size, true) as $chunk) { $chunks[] = new static($chunk); } return new static($chunks); } Language: PHP. Theme: Github Dark Combine Diffing and Focusing Combine both if you want, you have total control over how your code is presented. Take a look at the source tab to see how easy it is to annotate your code. Language: PHP Theme: Github Dark Result Source 1items, $size, true) as $chunk) {18 $chunks[] = new static($chunk);19 }20 21 return new static($chunks);22} items, $size, true) as $chunk) { $chunks[] = new static($chunk); } return new static($chunks); } Language: PHP. Theme: Github Dark Collapse Irrelevant Parts, Without JavaScript! Sometimes you want to build up an entire code example as you go, but not show every line on every step. With collapsing, you can keep your reader focused on the parts you're talking about, while also giving them the full context if they need it. As always, no JavaScript required! Take a look at the source tab to see how it's done using Torchlight's collapse annotation. Language: PHP Theme: Github Dark Result Source 1keyBy->id(); 8 9 // First set the html from the cache if it is already stored.10 $this->setHtmlFromCache($blocks);11 12 // Then reject all the blocks that already have the html, which13 // will leave us with only the blocks we need to request.14 $needed = $blocks->reject(function ($block) {15 return (bool)$block->html;16 });17 18 $needed = $blocks->reject->html;19 20 // If there are any blocks that don't have html yet,21 // we fire a request.22 if ($needed->count()) {23 // This method will set the html on the block objects,24 // so we don't do anything with the return value.25 $this->request($needed);26 }27 28 return $blocks->values()->toArray();29 } 30 31 protected function request(Collection $blocks) ...32 {33 $response = Http::timeout(5)34 ->withToken(config('torchlight.token'))35 ->post('https://torchlight.dev/api/highlight', [36 'blocks' => $blocks->map->toRequestParams()->values(),37 ])38 ->json();39 40 $response = collect($response['blocks'])->keyBy('id');41 42 $blocks->each(function (Block $block) use ($response) {43 $block->setHtml(44 $block->html ?? $this->getHtmlFromResponse($response, $block)45 );46 });47 48 $this->setCacheFromBlocks($blocks);49 50 return $blocks;51 } 52 53 public function cache()54 {55 $store = config('torchlight.cache');56 57 if ($store === null) {58 $store = config('cache.default');59 }60 61 return Cache::store($store);62 }63} keyBy->id(); // First set the html from the cache if it is already stored. $this->setHtmlFromCache($blocks); // Then reject all the blocks that already have the html, which // will leave us with only the blocks we need to request. $needed = $blocks->reject(function ($block) { return (bool)$block->html; }); $needed = $blocks->reject->html; // If there are any blocks that don't have html yet, // we fire a request. if ($needed->count()) { // This method will set the html on the block objects, // so we don't do anything with the return value. $this->request($needed); } return $blocks->values()->toArray(); } // [tl! collapse:end] protected function request(Collection $blocks) // [tl! collapse:start] { $response = Http::timeout(5) ->withToken(config('torchlight.token')) ->post('https://torchlight.dev/api/highlight', [ 'blocks' => $blocks->map->toRequestParams()->values(), ]) ->json(); $response = collect($response['blocks'])->keyBy('id'); $blocks->each(function (Block $block) use ($response) { $block->setHtml( $block->html ?? $this->getHtmlFromResponse($response, $block) ); }); $this->setCacheFromBlocks($blocks); return $blocks; } // [tl! collapse:end] public function cache() { $store = config('torchlight.cache'); if ($store === null) { $store = config('cache.default'); } return Cache::store($store); } } Language: PHP. Theme: Github Dark Insanely Easy Installation Torchlight is an API, with clients for popular backend languages. We currently have a Laravel Client, a Jigsaw Client, and a Commonmark PHP Client (which works with Statamic as well!) and a standalone CLI If you're using markdown, you add the extension and you're done! Using Blade views? You just use the Blade component instead of the normal code tag. 1
2 // Any code here will be highlighted by Torchlight!3 Did We Mention Themes? And Languages? Lots of themes. Lots of languages. 1items, $size, true) as $chunk) { 8 $chunks[] = new static($chunk); 9 }10 11 return new static($chunks);12} 1class Person 2 attr_reader :name, :age 3 4 def initialize(name, age) 5 @name, @age = name, age 6 end 7 8 def <=>(person) # the comparison operator for sorting 9 @age <=> person.age10 end11 12 def to_s13 "#{@name} (#{@age})"14 end15end16 17group = [18 Person.new("Bob", 33),19 Person.new("Chris", 16),20 Person.new("Ash", 23)21]22 23puts group.sort.reverse 1n = int(input('Type a number, and its factorial will be printed: ')) 2 3if n < 0: 4 raise ValueError('You must enter a non negative integer') 5 6fact = 1 7for i in range(2, n + 1): 8 fact *= i 9 10print(fact) 1defmodule Fun do2 def fib(0), do: 0+ def fib(1), do: 1 4 def fib(n), do: fib(n-2) + fib(n-1) 5end 1items, $size, true) as $chunk) { 8 $chunks[] = new static($chunk); 9 }10 11 return new static($chunks);12} 1items, $size, true) as $chunk) { 8 $chunks[] = new static($chunk); 9 }10 11 return new static($chunks);12} 1items, $size, true) as $chunk) { 8 $chunks[] = new static($chunk); 9 }10 11 return new static($chunks);12} 1items, $size, true) as $chunk) { 8 $chunks[] = new static($chunk); 9 }10 11 return new static($chunks);12} 1items, $size, true) as $chunk) { 8 $chunks[] = new static($chunk); 9 }10 11 return new static($chunks);12} 1items, $size, true) as $chunk) { 8 $chunks[] = new static($chunk); 9 }10 11 return new static($chunks);12} 1items, $size, true) as $chunk) { 8 $chunks[] = new static($chunk); 9 }10 11 return new static($chunks);12} 1items, $size, true) as $chunk) { 8 $chunks[] = new static($chunk); 9 }10 11 return new static($chunks);12} 1
2 3
8
15
16 Nothing left in the list. Add a new todo in the input above.17
18
19 1SELECT2 *3FROM4 `users`5 LEFT JOIN `addresses` ON `users`.`address_id` = `addresses`.`id`6WHERE7 `name` = 'Aaron' -- That's my name! 8 AND9 YEAR(`birthday`) = 1989 1items, $size, true) as $chunk) { 8 $chunks[] = new static($chunk); 9 }10 11 return new static($chunks);12} 1items, $size, true) as $chunk) { 8 $chunks[] = new static($chunk); 9 }10 11 return new static($chunks);12} 1
2 3
8
15
16 Nothing left in the list. Add a new todo in the input above.17
18
19 1items, $size, true) as $chunk) { 8 $chunks[] = new static($chunk); 9 }10 11 return new static($chunks);12} 1items, $size, true) as $chunk) { 8 $chunks[] = new static($chunk); 9 }10 11 return new static($chunks);12} 1items, $size, true) as $chunk) { 8 $chunks[] = new static($chunk); 9 }10 11 return new static($chunks);12} 1items, $size, true) as $chunk) { 8 $chunks[] = new static($chunk); 9 }10 11 return new static($chunks);12} 1items, $size, true) as $chunk) { 8 $chunks[] = new static($chunk); 9 }10 11 return new static($chunks);12} 1items, $size, true) as $chunk) { 8 $chunks[] = new static($chunk); 9 }10 11 return new static($chunks);12} 1items, $size, true) as $chunk) { 8 $chunks[] = new static($chunk); 9 }10 11 return new static($chunks);12} Pricing Plans Free for open source, a no-brainer for businesses. Monthly billing Yearly billing Personal / Open Source Free forever for non-revenue generating sites, attribution required. Sign Up For Free Plan → What's included All languages All themes A link back to torchlight.dev is required Non-revenue generating projects only Sponsor Sponsor the ongoing maintenance and development of the project. Start 7 Day Free Trial → What's included All languages All themes A link back to torchlight.dev is required Non-revenue generating projects only Business Low monthly cost for revenue generating sites, no attribution required. Start 7 Day Free Trial → What's included All languages All themes No attribution required Commercial use allowed 5,000 requests per month A Hammerstone, LLC Product. Built with Love & Care by Aaron in Dallas, Texas.
en
en
https://torchlight.dev
ཁྱོད་རའི་ས་ཁོངས་ཞུན་དག་འབད་ག?
ཁྱོད༌ག༌ཅི༌འབདཝ༌སྨོ?