github.com/xyproto/orbiton/v2@v2.65.12-0.20240516144430-e10a419274ec/template.go (about) 1 package main 2 3 import ( 4 "fmt" 5 "path/filepath" 6 "strings" 7 8 "github.com/xyproto/env/v2" 9 "github.com/xyproto/mode" 10 "github.com/xyproto/vt100" 11 ) 12 13 // TemplateProgram represents a string and cursor movement up, and then to the right 14 // which can be used to position the cursor after inserting a string. 15 type TemplateProgram struct { 16 text string 17 right int 18 up int 19 } 20 21 // TemplatePrograms maps from editor mode to simple example programs. 22 type TemplatePrograms map[mode.Mode]TemplateProgram 23 24 var templatePrograms TemplatePrograms 25 26 // GetTemplatePrograms will return a map from editor mode to per-programming-language template program. 27 // It is done this way to only initialize the map once, but not at the time when the program starts. 28 func GetTemplatePrograms() TemplatePrograms { 29 if templatePrograms == nil { 30 fullName := getFullName() 31 // NOTE: Cursor coordinates are (X, -Y) 32 templatePrograms = TemplatePrograms{ 33 mode.Agda: { 34 "module FILENAME where\n\nopen import Agda.Builtin.IO using (IO)\nopen import Agda.Builtin.Unit using (⊤)\nopen import Agda.Builtin.String using (String)\n\npostulate putStrLn : String → IO ⊤\n{-# FOREIGN GHC import qualified Data.Text as T #-}\n{-# COMPILE GHC putStrLn = putStrLn . T.unpack #-}\n\nmain : IO ⊤\nmain = putStrLn \"Hello, World!\"\n", 35 17, 36 1, 37 }, 38 mode.Algol68: { 39 "print((\"Hello, World!\", newline))\n", 40 8, 41 1, 42 }, 43 mode.Arduino: { 44 "void setup() {\n Serial.begin(9600);\n Serial.println(\"Hello, World!\");\n}\n\nvoid loop() {\n}\n", 45 16, 46 5, 47 }, 48 mode.C: { 49 "#include <stdio.h>\n#include <stdlib.h>\n\nint main(int argc, char* argv[])\n{\n\tprintf(\"%s\\n\", \"Hello, World!\");\n\treturn EXIT_SUCCESS;\n}\n", 50 8, 51 3, 52 }, 53 mode.Cpp: { 54 "#include <cstdlib>\n#include <iostream>\n#include <string>\n\nusing namespace std::string_literals;\n\nint main(int argc, char** argv)\n{\n std::cout << \"Hello, World!\"s << std::endl;\n return EXIT_SUCCESS;\n}\n", 55 14, 56 3, 57 }, 58 mode.Clojure: { 59 "(ns example.hello\n (:gen-class))\n\n(defn hello-world []\n (println \"Hello, World!\"))\n\n(hello-world)\n", 60 10, 61 3, 62 }, 63 mode.Crystal: { 64 "class Greeter\n def initialize(@name : String)\n end\n\n def greet\n puts \"Hello, #{@name}!\"\n end\nend\n\nGreeter.new(\"World\").greet\n", 65 6, 66 5, 67 }, 68 mode.CMake: { 69 "cmake_minimum_required(VERSION 3.5)\n\nproject(cmake-project-template)\n\nset(CMAKE_CXX_STANDARD 17)\nset(CMAKE_CXX_FLAGS \"${CMAKE_CXX_FLAGS} -std=c++17 -O2\")\n\nset(CMAKE_INSTALL_PREFIX ${PROJECT_SOURCE_DIR})\n\nset(DIVISIBLE_INSTALL_INCLUDE_DIR ${PROJECT_SOURCE_DIR}/include)\nset(DIVISIBLE_INSTALL_BIN_DIR ${PROJECT_SOURCE_DIR}/bin)\nset(DIVISIBLE_INSTALL_LIB_DIR ${PROJECT_SOURCE_DIR}/lib)\n\nset(DIVISION_HEADERS_DIR ${PROJECT_SOURCE_DIR}/src/division)\n\ninclude_directories(${DIVISIBLE_INSTALL_INCLUDE_DIR})\ninclude_directories(${DIVISION_HEADERS_DIR})\n\nadd_subdirectory(src)\nadd_subdirectory(test)\n", 70 8, 71 18, 72 }, 73 mode.CS: { 74 "using System;\n\nclass Greeter {\n public static void Main(string[] args) {\n Console.WriteLine(\"Hello, World!\");\n }\n}\n", 75 19, 76 3, 77 }, 78 mode.CSS: { 79 "body, h1, h2, h3, h4, h5, h6, p, ul, ol, li, figure, figcaption, blockquote, dl, dd {\n margin: 0;\n padding: 0;\n}\n\nbody {\n font-family: -apple-system, BlinkMacSystemFont, \"Segoe UI\", Roboto, Oxygen-Sans, Ubuntu, Cantarell, \"Helvetica Neue\", sans-serif;\n font-size: 16px; /* Good for readability */\n line-height: 1.6; /* Good for readability */\n color: #333; /* Sufficient contrast for readability */\n background-color: #fff; /* Light background to ensure contrast */\n}\n\na, button {\n color: #0066cc; /* Color should meet WCAG contrast ratio */\n text-decoration: none; /* Underlines can be confusing for some dyslexic users */\n}\n\na:hover, a:focus, button:hover, button:focus {\n text-decoration: underline; /* Indicate interactivity */\n outline: none; /* Custom focus styles are more visually appealing */\n}\n\n.container {\n width: 100%;\n margin-right: auto;\n margin-left: auto;\n padding-right: 15px;\n padding-left: 15px;\n}\n\n@media (min-width: 576px) { .container { max-width: 540px; } }\n@media (min-width: 768px) { .container { max-width: 720px; } }\n@media (min-width: 992px) { .container { max-width: 960px; } }\n@media (min-width: 1200px) { .container { max-width: 1140px; } }\n\n.padding-1 { padding: 0.25rem; }\n.padding-2 { padding: 0.5rem; }\n.padding-3 { padding: 1rem; }\n.margin-1 { margin: 0.25rem; }\n.margin-2 { margin: 0.5rem; }\n.margin-3 { margin: 1rem; }\n\n.flex-row {\n display: flex;\n flex-direction: row;\n}\n\n.flex-column {\n display: flex;\n flex-direction: column;\n}\n\n.justify-center {\n justify-content: center;\n}\n\n.align-center {\n align-items: center;\n}\n\nh1 { font-size: 2.25rem; }\nh2 { font-size: 1.8rem; }\nh3 { font-size: 1.5rem; }\nh4 { font-size: 1.2rem; }\nh5 { font-size: 1rem; }\nh6 { font-size: 0.875rem; }\n\n@media (max-width: 768px) {\n h1 { font-size: 2rem; }\n h2 { font-size: 1.75rem; }\n h3 { font-size: 1.5rem; }\n}\n\n:focus-visible {\n outline: 3px solid #ffbf47;\n outline-offset: 3px;\n}\n\nlabel {\n display: block;\n margin-bottom: .5rem;\n}\n\ninput, select, textarea, button {\n font: inherit; /* Ensure inputs use the same font */\n color: inherit; /* Ensure inputs use the same color */\n padding: .5rem;\n margin-bottom: 1rem; /* Space out elements */\n border: 1px solid #ccc; /* Slight border for definition */\n border-radius: 4px; /* Modern look with rounded corners */\n}\n\ninput:focus, select:focus, textarea:focus, button:focus {\n border-color: #0066cc;\n box-shadow: 0 0 0 3px rgba(0,102,204,0.25);\n}\n\nimg, video {\n max-width: 100%;\n height: auto;\n}\n", 80 1, 81 1, 82 }, 83 mode.D: { 84 "module main;\n\nimport std.stdio;\n\nvoid main(string[] args) {\n writeln(\"Hello, World!\");\n}\n", 85 9, 86 2, 87 }, 88 mode.Dart: { 89 "void main() {\n print('Hello, World!');\n}\n", 90 7, 91 2, 92 }, 93 mode.Email: { 94 "Hello ,\n\nBest regards,\n" + fullName + "\n", 95 6, 96 5, 97 }, 98 mode.Erlang: { 99 "-module(hello).\n-export([hello_world/0]).\n\nhello_world() -> io:fwrite(\"hello, world\\n\").\n", 100 29, 101 2, 102 }, 103 mode.Fortran77: { 104 "* Fortran 77\n PRINT *, 'Hello, World!'\n END\n", 105 10, 106 2, 107 }, 108 mode.Fortran90: { 109 "program hello\n ! Output the message\n print *, 'Hello, World!'\nend program hello\n", 110 10, 111 2, 112 }, 113 mode.Garnet: { 114 "fn main(): {} =\n __print_str(\"Hello, World!\")\nend\n", 115 10, 116 2, 117 }, 118 mode.GDScript: { // WIP 119 "extends Node\n\nexport var x = 42\nvar y = 64\n\nfunc _ready():\n\ty = 96\n\nfunc _process(delta):\n\ty = 128\n\n", 120 6, 121 5, 122 }, 123 mode.Go: { 124 "package main\n\nimport (\n\t\"fmt\"\n)\n\nfunc main() {\n\tfmt.Println(\"Hello, World!\")\n}\n", 125 13, 126 2, 127 }, 128 mode.Haxe: { 129 "class Main {\n static public function main():Void {\n trace(\"Hello, World!\");\n }\n}", 130 7, 131 2, 132 }, 133 mode.Hare: { 134 "use fmt;\n\nexport fn main() void = {\n fmt::println(\"Hello, World!\")!;\n};\n", 135 14, 136 2, 137 }, 138 mode.Haskell: { 139 "main :: IO ()\nmain = putStrLn \"Hello, World!\"\n", 140 17, 141 1, 142 }, 143 mode.HTML: { 144 "<!doctype html>\n<html lang=\"en\">\n <head>\n <meta charset=\"utf-8\">\n <meta name=\"viewport\" content=\"width=device-width, initial-scale=1\">\n <title>Hello</title>\n <meta name=\"description\" content=\"Hello\">\n <link rel=\"shortcut icon\" href=\"https://www.iconsdb.com/icons/download/orange/teapot-16.png\">\n <link rel=\"stylesheet\" href=\"https://unpkg.com/@picocss/pico@latest/css/pico.classless.min.css\">\n </head>\n <body>\n <header>\n <hgroup>\n <h1>Greetings</h1>\n <h2>About to greet <code>the world</code></h2>\n </hgroup>\n </header>\n <main>\n <section id=\"hello\">\n <h2>Hello, World!</h2>\n Task completed.\n </section>\n </main>\n <footer>\n All done.\n </footer>\n </body>\n</html>\n", 145 4, 146 9, 147 }, 148 mode.Inko: { 149 "import std.stdio.STDOUT\n\nclass async Main {\n fn async main {\n STDOUT.new.print('Hello, World!')\n }\n}\n", 150 18, 151 3, 152 }, 153 mode.Jakt: { 154 "function main() {\n println(\"Hello, World!\")\n}\n", 155 9, 156 2, 157 }, 158 mode.Java: { 159 "class Greeter {\n public static void main(String[] args) {\n System.out.println(\"Hello, World!\");\n }\n}\n", 160 20, 161 3, 162 }, 163 mode.JavaScript: { 164 "console.log('Hello, World!');\n", 165 13, 166 1, 167 }, 168 mode.Just: { 169 "#!/usr/bin/env just --justfile\n\nhello:\n\t@echo \"Hello, World!\"\n", 170 7, 171 1, 172 }, 173 mode.Koka: { 174 "fun main() {\n println(\"Hello, World!\")\n}\n", 175 9, 176 2, 177 }, 178 mode.Kotlin: { 179 "fun main() {\n println(\"Hello, World!\")\n}\n", 180 9, 181 2, 182 }, 183 mode.Lilypond: { 184 "\\version \"2.24.2\"\n\n\\score {\n \\relative c' {\n c d e f g a b c\n }\n}\n", 185 0, 186 3, 187 }, 188 mode.Lua: { 189 "print(\"Hello, World!\")\n", 190 7, 191 1, 192 }, 193 mode.Markdown: { 194 "# Title\n\n## Subtitle\n\ntext\n", 195 4, 196 1, 197 }, 198 mode.Mojo: { 199 "print(\"Hello, World!\")\n", 200 7, 201 1, 202 }, 203 mode.Nim: { 204 "echo \"Hello, World!\"\n", 205 6, 206 1, 207 }, 208 mode.ObjectPascal: { 209 "program Hello;\nconst\n greeting = 'Hello, World!';\nbegin\n writeln(greeting);\nend.\n", 210 12, 211 4, 212 }, 213 mode.OCaml: { 214 "print_string \"Hello world!\\n\"", 215 14, 216 2, 217 }, 218 mode.Odin: { 219 "package main\n\nimport \"core:fmt\"\n\nmain :: proc() {\n fmt.println(\"Hello, World!\");\n}\n", 220 13, 221 2, 222 }, 223 mode.Perl: { 224 "#!/usr/bin/env perl\n\nuse strict;\nuse utf8;\nuse warnings;\n\nbinmode(\\*STDOUT, \":utf8\");\nbinmode(\\*STDIN, \":utf8\");\nbinmode(\\*STDERR, \":utf8\");\n\nsub main {\n print(\"Hello, World!\\n\");\n}\n\nmain();\n", 225 7, 226 4, 227 }, 228 mode.Python: { 229 "#!/usr/bin/env python\n# -*- coding: utf-8 -*-\n\ndef main():\n print(\"Hello, World!\")\n\n\nif __name__ == \"__main__\":\n main()\n", 230 7, 231 5, 232 }, 233 mode.R: { 234 "print(\"Hello, World!\", quote=FALSE)", 235 7, 236 1, 237 }, 238 mode.Rust: { 239 "fn main() {\n println!(\"Hello, World!\");\n}\n", 240 10, 241 2, 242 }, 243 mode.Scala: { 244 "object Hello {\n\tdef main(args: Array[String]) = {\n\t\tprintln(\"Hello, World!\")\n\t}\n}\n", 245 9, 246 3, 247 }, 248 mode.Shell: { 249 "# Maintainer: " + fullName + " <" + env.Str("EMAIL", "email") + ">\n\npkgname=\npkgver=1.0.0\npkgrel=1\npkgdesc='Example application'\narch=(x86_64)\nurl='https://github.com/example/application'\nlicense=(BSD3)\nmakedepends=(git go)\nsource=(\"git+$url#commit=asdf\") # tag: v1.0.0\nb2sums=(SKIP)\n\nbuild() {\n cd $pkgname\n go build -v -mod=vendor -buildmode=pie -trimpath -ldflags=\"-s -w -extldflags \\\"${LDFLAGS}\\\"\"\n}\n\npackage() {\n install -Dm755 $pkgname/$pkgname \"$pkgdir/usr/bin/$pkgname\"\n install -Dm644 $pkgname/LICENSE \"$pkgdir/usr/share/licenses/$pkgname/LICENSE\"\n}\n", 250 8, 251 20, 252 }, 253 // This one is a bit more elaborate than strictly needed 254 mode.StandardML: { 255 "let\n val name = \"World\"\nin\n map (fn x => (print (\"Hello, \" ^ x ^ \"!\\n\"))) [name]\nend;", 256 22, 257 1, 258 }, 259 mode.Swift: { 260 "print(\"Hello, World!\")\n", 261 7, 262 1, 263 }, 264 mode.Teal: { 265 "print(\"Hello, World!\")\n", 266 7, 267 1, 268 }, 269 mode.TypeScript: { 270 "console.log('Hello, World!');\n", 271 13, 272 1, 273 }, 274 mode.V: { 275 "fn main() {\n name := 'World'\n println('Hello, $name!')\n}\n", 276 9, 277 2, 278 }, 279 mode.Zig: { 280 "const std = @import(\"std\");\n\npub fn main() !void {\n const stdout = std.io.getStdOut().writer();\n try stdout.print(\"Hello, World!\\n\", .{});\n}\n", 281 18, 282 2, 283 }, 284 } 285 } 286 return templatePrograms 287 } 288 289 // BaseFilenameWithoutExtension returns the base filename, without the extension 290 // For instance, "/some/where/main.c" becomes just "main". 291 func (e *Editor) BaseFilenameWithoutExtension() string { 292 baseFilename := filepath.Base(e.filename) 293 ext := filepath.Ext(baseFilename) 294 return strings.TrimSuffix(baseFilename, ext) 295 } 296 297 // InsertTemplateProgram will insert a template program at the current cursor position, 298 // if available. It will then reposition the cursor at an appropriate place in the template. 299 func (e *Editor) InsertTemplateProgram(c *vt100.Canvas) error { 300 prog, found := GetTemplatePrograms()[e.mode] 301 if !found { 302 return fmt.Errorf("could not find a template program for %s", e.mode) 303 } 304 305 baseFilenameWithoutExt := e.BaseFilenameWithoutExtension() 306 307 // If the mode is Go and this is a test file, insert a test template instead 308 if e.mode == mode.Go && strings.HasSuffix(baseFilenameWithoutExt, "_test") { 309 prog = TemplateProgram{ 310 "package main\n\nimport (\n\t\"testing\"\n)\n\nfunc TestSomething(t *testing.T) {\n\tt.Fail()\n}\n", 311 7, 312 2, 313 } 314 } 315 316 // Replace FILENAME with the base filename without extension, introduced because of Agda. 317 prog.text = strings.ReplaceAll(prog.text, "FILENAME", e.BaseFilenameWithoutExtension()) 318 319 // Insert the template program 320 e.InsertStringAndMove(c, prog.text) 321 322 // Move the cursor up and to the right 323 for x := 0; x < prog.up; x++ { 324 e.Up(c, nil) 325 } 326 for x := 0; x < prog.right; x++ { 327 e.Next(c) 328 } 329 330 return nil 331 }