{"id":13644275,"url":"https://github.com/adhocteam/pushup","last_synced_at":"2025-11-17T04:01:02.433Z","repository":{"id":65224778,"uuid":"523496502","full_name":"adhocteam/pushup","owner":"adhocteam","description":"Pushup is for making modern, page-oriented web apps in Go","archived":false,"fork":false,"pushed_at":"2025-03-14T17:12:32.000Z","size":4036,"stargazers_count":857,"open_issues_count":48,"forks_count":30,"subscribers_count":17,"default_branch":"main","last_synced_at":"2025-04-13T19:21:03.967Z","etag":null,"topics":["go","http","www"],"latest_commit_sha":null,"homepage":"https://pushup.adhoc.dev","language":"Go","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/adhocteam.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":"CONTRIBUTING.md","funding":null,"license":"LICENSE","code_of_conduct":"CODE_OF_CONDUCT.md","threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2022-08-10T21:04:59.000Z","updated_at":"2025-04-03T20:35:34.000Z","dependencies_parsed_at":"2024-04-04T23:21:33.792Z","dependency_job_id":"975ff58b-1b18-42a0-b7b8-69891c5d4078","html_url":"https://github.com/adhocteam/pushup","commit_stats":{"total_commits":281,"total_committers":11,"mean_commits":"25.545454545454547","dds":"0.32740213523131667","last_synced_commit":"0519a782c1c9fc7987728f1a71d408b2388d8c72"},"previous_names":[],"tags_count":2,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/adhocteam%2Fpushup","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/adhocteam%2Fpushup/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/adhocteam%2Fpushup/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/adhocteam%2Fpushup/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/adhocteam","download_url":"https://codeload.github.com/adhocteam/pushup/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":250014566,"owners_count":21360973,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["go","http","www"],"created_at":"2024-08-02T01:02:00.281Z","updated_at":"2025-11-17T04:00:57.362Z","avatar_url":"https://github.com/adhocteam.png","language":"Go","readme":"# Pushup - a page-oriented web framework for Go\n\n![workflow status](https://github.com/adhocteam/pushup/actions/workflows/go.yml/badge.svg)\n[![Contributor Covenant](https://img.shields.io/badge/Contributor%20Covenant-2.1-4baaaa.svg)](CODE_OF_CONDUCT.md)\n\n## Project status\n\nPushup is an experiment. In terms of the development life cycle, it should be considered **preview** pre-release software: it is largely functional, likely has significant bugs (including potential for data loss) and/or subpar performance, but is suitable for demos and testing. It has a decent unit test suite, including fuzzing test cases for the parser. Don't count on it for anything serious yet, and expect significant breaking changes. \n\n![screenshot of syntax highlighting of an example Pushup page](./example-syntax-highlighting.png)\n\n-   [Pushup - a page-oriented web framework for Go](#pushup---a-page-oriented-web-framework-for-go)\n    -   [What is Pushup?](#what-is-pushup)\n        -   [Pages in Pushup](#pages-in-pushup)\n    -   [Quick start with Docker](#quick-start-with-docker)\n    -   [Getting started](#getting-started)\n        -   [Installing Pushup](#installing-pushup)\n            -   [Prerequisites](#prerequisites)\n            -   [Install an official release](#install-an-official-release)\n            -   [Install via Nix](#install-via-nix)\n            -   [Install via git](#install-via-git)\n            -   [Install via `go install`](#install-via-go-install)\n        -   [Creating a new Pushup project](#creating-a-new-pushup-project)\n    -   [Example demo app](#example-demo-app)\n    -   [Go modules and Pushup projects](#go-modules-and-pushup-projects)\n    -   [Project directory structure](#project-directory-structure)\n    -   [Pages](#pages)\n    -   [Layouts](#layouts)\n    -   [Static media](#static-media)\n    -   [File-based routing](#file-based-routing)\n        -   [Dynamic routes](#dynamic-routes)\n    -   [Enhanced hypertext](#enhanced-hypertext)\n        -   [Inline partials](#inline-partials)\n    -   [Basic web framework functionality](#basic-web-framework-functionality)\n        -   [Escaping](#escaping)\n    -   [Pushup syntax](#pushup-syntax)\n        -   [How it works](#how-it-works)\n        -   [Directives](#directives)\n            -   [`^import`](#import)\n            -   [`^layout`](#layout)\n                -   [`^layout !` - no layout](#layout----no-layout)\n        -   [Go code blocks](#go-code-blocks)\n            -   [`^{`](#)\n            -   [`^handler`](#handler)\n        -   [Control flow statements](#control-flow-statements)\n            -   [`^if`](#if)\n            -   [`^for`](#for)\n        -   [Expressions](#expressions)\n            -   [Simple expressions](#simple-expressions)\n            -   [Explicit expressions](#explicit-expressions)\n        -   [Layout and templates](#layout-and-templates)\n            -   [`^section`](#section)\n            -   [`^partial`](#partial)\n    -   [Vim syntax file](#vim-syntax-file)\n\nPushup is an experimental new project that is exploring the viability of a new\napproach to web frameworks in Go.\n\nPushup seeks to make building page-oriented, server-side web apps using Go\neasy. It embraces the server, while acknowledging the reality of modern web\napps and their improvements to UI interactivity over previous generations.\n\n## What is Pushup?\n\nPushup is a program that compiles projects developed with the Pushup markup\nlanguage into standalone web app servers.\n\nThere are three main aspects to Pushup:\n\n1. An opinionated project/app directory structure that enables **file-based\n   routing**,\n1. A **lightweight markup** alternative to traditional web framework templates\n   that combines Go code for control flow and imperative, view-controller-like\n   code with HTML markup, and\n1. A **compiler** that parses that markup and generates pure Go code,\n   building standalone web apps on top of the Go stdlib `net/http` package.\n\n### Pages in Pushup\n\nThe core object in Pushup is the \"page\": a file with the `.up` extension that\nis a mix of HTML, Go code, and a lightweight markup language that glues them\ntogether. Pushup pages participate in URL routing by virtue of their path in\nthe filesystem. Pushup pages are compiled into pure Go which is then built\nalong with a thin runtime into a standalone web app server (which is all\n`net/http` under the hood).\n\nThe main proposition motivating Pushup is that the page is the right level of\nabstraction for most kinds of server-side web apps.\n\nThe syntax of the Pushup markup language looks like this:\n\n```pushup\n\n^import \"time\"\n\n^{\n    title := \"Hello, from Pushup!\"\n}\n\n\u003ch1\u003e^title\u003c/h1\u003e\n\n\u003cp\u003eThe time is now ^time.Now().String().\u003c/p\u003e\n\n^if time.Now().Weekday() == time.Friday {\n    \u003cp\u003eIt's Friday! Enjoy the start to your weekend.\u003c/p\u003e\n} ^else {\n    \u003cp\u003eHave a great day, we're glad you're here.\u003c/p\u003e\n}\n\n```\n\nYou would then place this code in a file somewhere in your `app/pages`\ndirectory, like `hello.up`. The `.up` extension is important and tells\nthe compiler that it is a Pushup page. Once you build and run your Pushup app,\nthat page is automatically mapped to the URL path `/hello`.\n\n## Quick start with Docker\n\n```shell\ngit clone https://github.com/adhocteam/pushup.git\ncd pushup\nmake build-docker\n```\n\nThen create a scaffolded new project in the current directory:\n\n```shell\ndocker run --rm -v $(pwd):/usr/src/app --user $(id -u):$(id -g) pushup new myproject\ncd myproject\ndocker run --rm -v $(pwd):/usr/src/app --user $(id -u):$(id -g) -p 8080:8080 pushup run\n```\n\nSee [Creating a new Pushup project](#creating-a-new-pushup-project) for more information.\n\n## Getting started\n\nTo make a new Pushup app, first install the main Pushup executable.\n\n### Installing Pushup\n\n#### Prerequisites\n\n-   go 1.18 or later\n\nMake sure the directory where the go tool installs executables is in your\n`$PATH`. It is `$(go env GOPATH)/bin`. You can check if this is the case with:\n\n```shell\necho $PATH | grep $(go env GOPATH)/bin \u003e /dev/null \u0026\u0026 echo yes || echo no\n```\n\n#### Install an official release\n\nDownload Pushup for your platform from [the releases page](https://github.com/adhocteam/pushup/releases).\n\n#### Install via Nix\n\nPushup is available via the [Nix](https://nixos.org/) package manager. It is\ncurrently in the [`unstable` channel](https://search.nixos.org/packages?channel=unstable\u0026query=pushup).\n\n* **Add to your local profile**\n\n```shell\n$ nix-env -iA nixpkgs.pushup\n```\n\n* **Create a temporary shell**\n\n```shell\n$ nix-shell -p pushup\n```\n\n* **Create a temporary shell (flakes)**\n\n```shell\n$ nix shell nixpkgs#pushup\n```\n\n* **Run Pushup without installing (flakes)**\n\n```shell\n$ nix run nixpkgs#pushup\n````\n\n#### Install via git\n\n```shell\ngit clone git@github.com:AdHocRandD/pushup.git\ncd pushup\nmake\n```\n\n#### Install via `go install`\n\nMake sure you have Go installed (at least version 1.18), and type:\n\n```shell\ngo install github.com/adhocteam/pushup@latest\n```\n\n### Creating a new Pushup project\n\nTo create a new Pushup project, use the `pushup new` command.\n\n```shell\npushup new\n```\n\nWithout any additional arguments, it will attempt to create a scaffolded new\nproject in the current directory. However, the directory must be completely\nempty, or the command will abort. To simulataneously make a new directory\nand generate a scaffolded project, pass a relative path as argument:\n\n```shell\npushup new myproject\n```\n\nThe scaffolded new project directory consists of a directory structure for\n.up files and auxiliary project Go code, and a go.mod file.\n\nChange to the new project directory if necessary, then do a `pushup run`,\nwhich compiles the Pushup project to Go code, builds the app, and starts up\nthe server.\n\n```shell\npushup run\n```\n\nIf all goes well, you should see a message on the terminal that the Pushup app\nis running and listening on a port:\n\n```\n↑↑ Pushup ready and listening on 0.0.0.0:8080 ↑↑\n```\n\nBy default it listens on port 8080, but with the `-port` or `-unix-socket`\nflags you can pick your own listener.\n\nOpen [http://localhost:8080/](http://localhost:8080/) in your browser to see\nthe default layout and a welcome index page.\n\n## Example demo app\n\nSee the [example](./example) directory for a demo Pushup app that demonstrates\nmany of the concepts in Pushup and implements a few small common patterns like\nsome HTMX examples and a simple CRUD app.\n\nClick on \"view source\" at the bottom of any page in the example app to see the\nsource of the .up page for that route, including the source of the \"view\nsource\" .up page itself. This is a good way to see how to write Pushup\nsyntax.\n\n## Go modules and Pushup projects\n\nPushup treats projects as their own self-contained Go module. The build\nprocess assumes this is the case by default. But it is possible to include a\nPushup project as part of a parent Go module. See the the `-module` option to\n`pushup new`.\n\n## Project directory structure\n\nPushup projects have a particular directory structure that the compiler expects\nbefore building. The most minimal Pushup project would look like:\n\n```\napp\n├── layouts\n├── pages\n│   └── index.up\n├── pkg\n└── static\ngo.mod\n```\n\n## Pages\n\nPushup pages are the main units in Pushup. They are a combination of logic and\ncontent. It may be helpful to think of them as both the controller and the view\nin a MVC-like system, but colocated together in the same file.\n\nThey are also the basis of file-based routing: the name of the Pushup file,\nminus the .up extension, is mapped to the portion of the URL path for\nrouting.\n\n## Layouts\n\nLayouts are HTML templates that used in common across multiple pages. They are\njust HTML, with Pushup syntax as necessary. Each page renders its contents, and\nthen the layout inserts the page contents into the template with the\n`^outputSection(\"contents\")` Pushup expression.\n\n## Static media\n\nStatic media files like CSS, JS, and images, can be added to the `app/static`\nproject directory. These will be embedded directly in the project executable\nwhen it is built, and are accessed via a straightforward mapping under the\n\"/static/\" URL path.\n\n## File-based routing\n\nPushup maps file locations to URL route paths. So `about.up` becomes\n`/about`, and `foo/bar/baz.up` becomes `/foo/bar/baz`. More TK ...\n\nYou can print a list of the app's routes with the command:\n\n```shell\npushup routes\n```\n\n### Dynamic routes\n\nIf the filename of a Pushup page starts with a `$` dollar sign, the portion\nof the URL path that matches will be available to the page via the `getParam()`\nPushup API method.\n\nFor example, let's say there is a Pushup page at `app/pages/people/$id.up`.\nIf a browser visits the URL `/people/1234`, the page can access it like a named\nparameter with the API method `getParam()`, for example:\n\n```pushup\n\u003cp\u003eID: ^getParam(req, \"id\")\u003c/p\u003e\n```\n\nwould output:\n\n```html\n\u003cp\u003eID: 1234\u003c/p\u003e\n```\n\nThe name of the parameter is the word following the `$` dollar sign, up to a dot\nor a slash. Conceptually, the URL route is `/people/:id`, where `:id` is the\nnamed parameter that is substituted for the actual value in the request URL.\n\nDirectories can be dynamic, too. `app/pages/products/$pid/details.up` maps\nto `/products/:pid/details`.\n\nMultiple named parameters are allowed, for example, `app/pages/users/$uid/projects/$pid.up`\nmaps to `/users/:uid/projects/:pid`.\n\n## Enhanced hypertext\n\n### Inline partials\n\nInline partials allow pages to denote subsections of themselves, and allow\nfor these subsections (the inline partials) to be rendered and returned to\nthe client independently, without having to render the entire enclosing page.\n\nTypically, partials in templating languages are stored in their own files,\nwhich are then transcluded into other templates. Inline partials, however, are\npartials declared and defined in-line a parent or including template.\n\nInline partials are useful when combined with enhanced hypertext solutions\n(eg., [htmx](https://htmx.org/)). The reason is that these sites make AJAX\nrequests for partial HTML responses to update portions of an already-loaded\ndocument. Partial responses should not have enclosing markup such as base\ntemplates applied by the templating engine, since that would break the of the\ndocument they are being inserted into. Inline partials in Pushup automatically\ndisable layouts so that partial responses have just the content they define.\n\nThe ability to quickly define partials, and not have to deal with complexities\nlike toggling off layouts, makes it easier to build enhanced hypertext sites.\n\n## Basic web framework functionality\n\nAll modern web frameworks should implement a standard set of functionality,\nspanning from safety to convenience. As of this writing, Pushup does not yet\nimplement them all, but aspires to prior to any public release.\n\n### Escaping\n\nBy default, all content is HTML-escaped, so in general it is safe to directly\nplace user-supplied data into Pushup pages. (Note that the framework does\nnot (yet) do this in your Go code, data from form submissions and URL queries\nshould be validated and treated as unsafe.)\n\nFor example, if you wanted to display on the page the query a user searched for,\nthis is safe:\n\n```pushup\n^{ query := req.FormValue(\"query\") }\n\u003cp\u003eYou search for: \u003cb\u003e^query\u003c/b\u003e\u003c/p\u003e\n```\n\n## Pushup syntax\n\n### How it works\n\nPushup is a mix of a new syntax consisting of Pushup directives and keywords,\nGo code, and HTML markup.\n\nParsing a .up file always starts out in HTML mode, so you can just put\nplain HTML in a file and that's a valid Pushup page.\n\nWhen the parser encounters a '^' character (caret, ASCII 0x5e) while in\nHTML mode, it switches to parsing Pushup syntax, which consists of simple\ndirectives, control flow statements, block delimiters, and Go expressions. It\nthen switches to the Go code parser. Once it detects the end of the directive,\nstatement, or expression, it switches back to HTML mode, and parsing continues\nin a similar fashion.\n\nPushup uses the tokenizers from the [go/scanner][scannerpkg] and\n[golang.org/x/net/html][htmlpkg] packages, so it should be able to handle\nany valid syntax from either language.\n\n### Directives\n\n#### `^import`\n\nUse `^import` to import a Go package into the current Pushup page. The syntax\nfor `^import` is the same as a regular [Go import declaration](https://go.dev/ref/spec#Import_declarations)\n\nExample:\n\n```pushup\n^import \"strings\"\n^import \"strconv\"\n```\n\n```pushup\n^import . \"strings\"\n```\n\n#### `^layout`\n\nLayouts are HTML templates that enclose the contents of a Pushup page.\n\nThe `^layout` directive instructs Pushup what layout to apply the contents of\nthe current page.\n\nThe name of the layout following the directive is the filename in the\n`layouts` directory minus the `.up` extension. For example, `^layout main`\nwould try to apply the layout located at `app/layouts/main.up`.\n\n`^layout` is optional - if it is not specified, pages automatically get the\n\"default\" layout (`app/layouts/default.up`).\n\nExample:\n\n```pushup\n^layout homepage\n```\n\n##### `^layout !` - no layout\n\nA page may choose to have no layout applied - that is, the contents of the page\nitself are sent directly to the client with no enclosing template. In this case,\nuse the `!` name:\n\n```pushup\n^layout !\n```\n\n### Go code blocks\n\n#### `^{`\n\nTo include statements of Go in a Pushup page, type `^{` followed by your\nGo code, terminating with a closing `}`.\n\nThe scope of a `^{ ... }` in the compiled Go code is equal to its surrounding\nmarkup, so you can define a variable and immediately use it:\n\n```pushup\n^{\n\tname := \"world\"\n}\n\u003ch1\u003eHello, ^name!\u003c/h1\u003e\n```\n\nBecause the Pushup parser is only looking for a balanced closing `}`, blocks\ncan be one-liners:\n\n```pushup\n^{ name := \"world\"; greeting := \"Hello\" }\n\u003ch1\u003e^greeting, ^name!\u003c/h1\u003e\n```\n\nA Pushup page can have zero or many `^{ ... }` blocks.\n\n#### `^handler`\n\nA handler is similar to `^{ ... }`. The difference is that there may be at most\none handler per page, and it is run prior to any other code or markup on the\npage.\n\nA handler is the appropriate place to do \"controller\"-like (in the MVC sense)\nactions, such as HTTP redirects and errors. In other words, any control flow\nbased on the nature of the request, for example, redirecting after a successful\nPOST to create a new object in a CRUD operation.\n\nExample:\n\n```pushup\n^handler {\n    if req.Method == \"POST\" \u0026\u0026 formValid(req) {\n\t\tif err := createObjectFromForm(req.Form); err == nil {\n\t\t\treturn http.Redirect(w, req, \"/success/\", http.StatusSeeOther)\n\t\t\treturn nil\n\t\t} else {\n\t\t\t// error handling\n\t\t\t...\n\t}\n\t...\n}\n...\n```\n\nNote that handlers (and all Pushup code) run in a method on a receiver that\nimplements Pushup's `Responder` interface, which is\n\n```go\ninterface Responder {\n\tRespond(http.ResponseWriter, *http.Request) error\n}\n```\n\nTo exit from a page early in a handler (i.e., prior to any normal content being\nrendered), return from the method with a nil (for success) or an error (which\nwill in general respond with HTTP 500 to the client).\n\n### Control flow statements\n\n#### `^if`\n\n`^if` takes a boolean Go expression and a block to conditionally render.\n\nExample:\n\n```pushup\n^if query := req.FormValue(\"query\"); query != \"\" {\n\t\u003cp\u003eQuery: ^query\u003c/p\u003e\n}\n```\n\n#### `^for`\n\n`^for` takes a Go \"for\" statement condition, clause, or range, and a block,\nand repeatedly executes the block.\n\nExample:\n\n```pushup\n^for i := 0; i \u003c 10; i++ {\n\t\u003cp\u003eNumber ^i\u003c/p\u003e\n}\n```\n\n### Expressions\n\n#### Simple expressions\n\nSimple Go expressions can be written with just `^` followed by the expression.\n\"Simple\" means:\n\n-   variable names (eg., `^x`)\n-   dotted field name access of structs (eg., `^account.name`)\n-   function and method calls (eg., `^strings.Repeat(\"x\", 3)`)\n-   index expressions (eg., `a[x]`)\n\nExample:\n\n```pushup\n^{ name := \"Paul\" }\n\u003cp\u003eHello, ^name!\u003c/p\u003e\n```\n\nOutputs:\n\n```html\n\u003cp\u003eHello, Paul!\u003c/p\u003e\n```\n\nNotice that the parser stops on the \"!\" because it knows it is not part of a\nGo variable name.\n\nExample:\n\n```pushup\n\u003cp\u003eThe URL path: ^req.URL.Path\u003c/p\u003e\n```\n\nOutputs:\n\n```html\n\u003cp\u003eThe URL path: /foo/bar\u003c/p\u003e\n```\n\nExample:\n\n```pushup\n^import \"strings\"\n\u003cp\u003e^strings.Repeat(\"Hello\", 3)\u003c/p\u003e\n```\n\nOutputs:\n\n```html\n\u003cp\u003eHelloHelloHello\u003c/p\u003e\n```\n\n#### Explicit expressions\n\nExplicit expressions are written with `^` and followed by any valid Go\nexpression grouped by parentheses.\n\nExample:\n\n```pushup\n^{ numPeople := 4 }\n\u003cp\u003eWith ^numPeople people there are ^(numPeople * 2) hands\u003c/p\u003e\n```\n\nOutputs:\n\n```html\n\u003cp\u003eWith 4 people there are 8 hands\u003c/p\u003e\n```\n\n### Layout and templates\n\n#### `^section`\n\nPushup layouts can have sections within the HTML document that Pushup pages\ncan define with their own content to be rendered into those locations.\n\nFor example, a layout could have a sidebar section, and each page can set\nits own sidebar content.\n\nIn a Pushup page, sections are defined with the keyword like so:\n\n```pushup\n^section sidebar {\n    \u003carticle\u003e\n        \u003ch1\u003eThis is my sidebar content\u003c/h1\u003e\n        \u003cp\u003eMore to come\u003c/p\u003e\n    \u003c/article\u003e\n}\n```\n\nLayouts can output sections with the `outputSection` function.\n\n```pushup\n\u003caside\u003e\n    ^outputSection(\"sidebar\")\n\u003c/aside\u003e\n```\n\nLayouts can also make sections optional, by first checking if a page has set a\nsection with `sectionDefined()`, which returns a boolean.\n\n```pushup\n^if sectionDefined(\"sidebar\") {\n    \u003caside\u003e\n        ^outputSection(\"sidebar\")\n    \u003c/aside\u003e\n}\n```\n\nChecking for if a section was set by a page lets a layout designer provide\ndefault markup that can be overridden by a page.\n\n```pushup\n^if sectionDefined(\"title\") {\n    \u003ctitle\u003e\n        ^outputSection(\"title\")\n    \u003c/title\u003e\n} ^else {\n    \u003ctitle\u003eWelcome to our site\u003c/title\u003e\n}\n```\n\n#### `^partial`\n\nPushup pages can declare and define inline partials with the `^partial`\nkeyword.\n\n```pushup\n...\n\u003csection\u003e\n    \u003cp\u003eElements\u003c/p\u003e\n    ^partial list {\n            \u003cul\u003e\n                \u003cli\u003eAg\u003c/li\u003e\n                \u003cli\u003eNa\u003c/li\u003e\n                \u003cli\u003eC\u003c/li\u003e\n            \u003c/ul\u003e\n    }\n\u003c/section\u003e\n...\n```\n\nA request to the page containing the initial partial will render normally,\nas if the block where not wrapped in `^partial list {` ... `}`.\n\nA request to the page with the name of the partial appended to the URL path\nwill respond with just the content scoped by the partial block.\n\nFor example, if the page above had the route `/elements/`, then a request to\n`/elements/list` would output:\n\n```html\n\u003cul\u003e\n    \u003cli\u003eAg\u003c/li\u003e\n    \u003cli\u003eNa\u003c/li\u003e\n    \u003cli\u003eC\u003c/li\u003e\n\u003c/ul\u003e\n```\n\nInline partials can nest arbitrarily deep.\n\n```pushup\n...\n^partial leagues {\n    \u003cp\u003eLeagues\u003c/p\u003e\n    ^partial teams {\n        \u003cp\u003eTeams\u003c/p\u003e\n        ^partial players {\n            \u003cp\u003ePlayers\u003c/p\u003e\n        }\n    }\n}\n...\n```\n\nTo request a nested partial, make sure the URL path is preceded by\neach containing partial's name and a forward slash, for example,\n`/sports/leagues/teams/players`.\n\n[token]: https://docs.github.com/en/authentication/keeping-your-account-and-data-secure/creating-a-personal-access-token\n[scannerpkg]: https://pkg.go.dev/go/scanner#Scanner\n[htmlpkg]: https://pkg.go.dev/golang.org/x/net/html#Tokenizer\n\n## Vim syntax file\n\nThere is a vim plugin in the `vim-pushup` directory. You should be able to symlink it into your plugin manager's path. Alternatively, to install it manually:\n\n-   Locate or create a `syntax` directory in your vim config directory (Usually `~/.vim/syntax` for vim or `~/.config/nvim/syntax` for neovim)\n-   Copy [`syntax/pushup.vim`](https://github.com/adhocteam/pushup/blob/main/vim-pushup/syntax/pushup.vim) into that directory\n-   Locate or create a `ftdetect` directory in your vim config directory (Usually `~/.vim/ftdetect` for vim or `~/.config/nvim/ftdetect` for neovim)\n-   Copy [`ftdetect/pushup.vim`](https://github.com/adhocteam/pushup/blob/main/vim-pushup/ftdetect/pushup.vim) into that directory\n","funding_links":[],"categories":["Examples by Back-end","Go"],"sub_categories":["Go"],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fadhocteam%2Fpushup","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fadhocteam%2Fpushup","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fadhocteam%2Fpushup/lists"}