wip7
This commit is contained in:
@@ -0,0 +1,223 @@
|
||||
---
|
||||
# icon: material/architecture
|
||||
tags: ["iptvc", "разработка", "архитектура"]
|
||||
---
|
||||
|
||||
# Архитектура iptvc
|
||||
|
||||
Внутреннее устройство программы для разработчиков.
|
||||
|
||||
## Стек технологий
|
||||
|
||||
- **Go 1.22+** — язык программирования;
|
||||
- `net/http` — HTTP-сервер (Go 1.22 routing patterns);
|
||||
- `html/template` — шаблоны HTML;
|
||||
- `//go:embed` — встраивание шаблонов в бинарник;
|
||||
- `github.com/spf13/cobra` — CLI-фреймворк;
|
||||
- `gopkg.in/yaml.v3` — парсинг `config.yml`;
|
||||
- `github.com/joho/godotenv` — загрузка `.env`;
|
||||
- `github.com/redis/go-redis/v9` — клиент KeyDB/Redis.
|
||||
|
||||
## Структура проекта
|
||||
|
||||
```
|
||||
iptvc/
|
||||
├── main.go # точка входа
|
||||
├── config.yml # конфигурация
|
||||
├── .env # переменные окружения (опционально)
|
||||
├── cmd/ # CLI-команды (Cobra)
|
||||
│ ├── root.go # корневая команда, глобальные флаги
|
||||
│ ├── check.go # команда check
|
||||
│ ├── serve.go # команда serve
|
||||
│ ├── flags.go # общие флаги check/serve
|
||||
│ └── version.go # команда version
|
||||
├── app/
|
||||
│ ├── app.go # глобальные переменные: Args, Config, Cache
|
||||
│ ├── config/
|
||||
│ │ └── config.go # Config, Init(), validate(), IntRange, UserAgents
|
||||
│ ├── checker/
|
||||
│ │ └── checker.go # CheckPlaylists(), CheckChannels(), OnPlaylistChecked
|
||||
│ ├── playlist/
|
||||
│ │ └── playlist.go # Playlist, Channel, Parse(), Download()
|
||||
│ ├── inifile/
|
||||
│ │ └── inifile.go # чтение playlists.ini
|
||||
│ ├── tagfile/
|
||||
│ │ └── tagfile.go # чтение channels.json, назначение тегов
|
||||
│ ├── cache/
|
||||
│ │ └── cache.go # подключение к KeyDB/Redis
|
||||
│ ├── logger/
|
||||
│ │ └── logger.go # настройка логирования
|
||||
│ ├── utils/
|
||||
│ │ └── utils.go # Fetch(), ExpandPath(), ArrayUnique(), Md5str()
|
||||
│ └── web/
|
||||
│ ├── server.go # Server, Start(), StartBackgroundChecker()
|
||||
│ ├── handlers.go # HTTP-обработчики
|
||||
│ ├── templates.go # TemplateManager, //go:embed
|
||||
│ └── views/ # HTML-шаблоны
|
||||
│ ├── base.html
|
||||
│ ├── list.html
|
||||
│ ├── details.html
|
||||
│ └── notfound.html
|
||||
└── go.mod
|
||||
```
|
||||
|
||||
## Пакеты
|
||||
|
||||
### `app`
|
||||
|
||||
Глобальный контейнер: `Args` (CLI-флаги), `Config` (конфигурация), `Cache` (Redis-клиент).
|
||||
`Init()` загружает конфигурацию, инициализирует логгер и подключение к кешу.
|
||||
|
||||
### `app.config`
|
||||
|
||||
Структуры: `Config` → `AppConfig`, `ServerConfig`, `CheckConfig`, `CacheConfig`.
|
||||
|
||||
Кастомные YAML-типы:
|
||||
|
||||
- **`IntRange`** — скаляр или `[min, max]`. Метод `Value()` возвращает константу или случайное значение.
|
||||
- **`UserAgents`** — строка или массив строк. Метод `Pick()` возвращает случайный элемент.
|
||||
|
||||
`Init(configPath)` — загружает `config.yml`, применяет env, валидирует.
|
||||
|
||||
`validate()` — проверяет все значения, исправляет некорректные с логированием.
|
||||
|
||||
### `app.checker`
|
||||
|
||||
Содержит логику проверки:
|
||||
|
||||
- **`PrepareListsToCheck(files, urls, codes)`** — формирует список плейлистов из файлов, URL и кодов ini-файла.
|
||||
- **`CheckPlaylists(lists)`** — параллельная проверка плейлистов (семфор `per-routine`), загрузка, парсинг, вызов `CheckChannels` для каждого.
|
||||
- **`CheckChannels(pls)`** — параллельная проверка каналов (семфор `per-routine`), HTTP-запрос с `Range` header.
|
||||
- **`OnPlaylistChecked`** — глобальный callback, вызывается после проверки каждого плейлиста. Используется веб-сервером для обновления in-memory кеша.
|
||||
- **`cachePlaylist(pls)`** — сохранение результата в Redis (если включён).
|
||||
|
||||
Параметры проверки берутся из `app.Config.Check.Playlists` и `app.Config.Check.Channels`.
|
||||
|
||||
### `app.playlist`
|
||||
|
||||
- **`Playlist`** — плейлист: код, URL, контент, каналы, статус.
|
||||
- **`Channel`** — канал: ID, название, URL, статус, теги.
|
||||
- **`Download(userAgent, timeout)`** — загрузка по URL.
|
||||
- **`ReadFromFs()`** — чтение из файла.
|
||||
- **`Parse()`** — парсинг m3u/m3u8 контента.
|
||||
|
||||
### `app.web`
|
||||
|
||||
Веб-сервер на `net/http` (Go 1.22 routing).
|
||||
|
||||
- **`Server`** — структура: конфиг, кеш, шаблоны, in-memory кеш (`memCache` с `sync.RWMutex`).
|
||||
- **`Start()`** — запуск HTTP-сервера.
|
||||
- **`StartBackgroundChecker(opts)`** — фоновая проверка в отдельной горутине.
|
||||
- **`CheckOptions`** — параметры: Every, Repeat, Random, Files, Urls, Codes.
|
||||
|
||||
Маршруты (Go 1.22 patterns):
|
||||
|
||||
```
|
||||
GET /api/playlists/{code} — JSON плейлиста
|
||||
GET /api/version — версия
|
||||
GET /api/health — здоровье сервиса
|
||||
GET /api/stats — статистика
|
||||
GET /{$} — главная (catch-all root)
|
||||
GET /{path...} — все остальные маршруты (catch-all)
|
||||
```
|
||||
|
||||
Catch-all `/{path...}` используется для избежания конфликтов паттернов в Go 1.22 mux.
|
||||
|
||||
In-memory кеш (`memCache`) обновляется через `OnPlaylistChecked` callback.
|
||||
Это позволяет отображать результаты проверки в реальном времени без ожидания завершения цикла и без Redis.
|
||||
|
||||
ini-файл кешируется на 30 секунд, кеш сбрасывается при каждом обновлении `memCache`.
|
||||
|
||||
## Жизненный цикл `serve --check`
|
||||
|
||||
```
|
||||
main → app.Init() → web.NewServer() → go StartBackgroundChecker() → server.Start()
|
||||
|
||||
StartBackgroundChecker:
|
||||
loop:
|
||||
runCheckerOnce()
|
||||
→ checker.PrepareListsToCheck()
|
||||
→ checker.CheckPlaylists()
|
||||
→ for each playlist (parallel, per-routine):
|
||||
→ Download() / ReadFromFs()
|
||||
→ Parse()
|
||||
→ CheckChannels()
|
||||
→ for each channel (parallel, per-routine):
|
||||
→ HTTP GET with Range header
|
||||
→ check status + content type
|
||||
→ OnPlaylistChecked(pls) → memCache update
|
||||
→ one-cooldown sleep
|
||||
→ all-cooldown sleep
|
||||
sleep(every)
|
||||
if repeat > 0 && iteration >= repeat: stop
|
||||
```
|
||||
|
||||
## CLI-флаги
|
||||
|
||||
### Общие (`cmd/flags.go`)
|
||||
|
||||
Используются командами `check` и `serve --check`:
|
||||
|
||||
| Флаг | Поле | Описание |
|
||||
| -------------------------- | -------------------- | ---------------------------------- |
|
||||
| `-i, --ini` | `Args.IniPath` | Путь к playlists.ini |
|
||||
| `-t, --tags` | `Args.TagsPath` | Путь к channels.json |
|
||||
| `-r, --random` | `Args.RandomCount` | Случайные N плейлистов |
|
||||
| `--repeat` | `Args.RepeatCount` | Количество циклов (0 = бесконечно) |
|
||||
| `--playlists-all-cooldown` | `Args.PlAllCooldown` | Миллисекунд между циклами |
|
||||
|
||||
### Только `check` (`addCheckOnlyFlags`)
|
||||
|
||||
| Флаг | Поле | Описание |
|
||||
| ------------- | ---------------- | ------------------- |
|
||||
| `-j, --json` | `Args.NeedJson` | Вывод в JSON |
|
||||
| `-q, --quiet` | `Args.NeedQuiet` | Подавить логи |
|
||||
| `-f, --file` | `Args.Files` | Локальные m3u файлы |
|
||||
| `-u, --url` | `Args.Urls` | URL плейлистов |
|
||||
| `-c, --code` | `Args.Codes` | Коды из ini-файла |
|
||||
|
||||
### Только `serve`
|
||||
|
||||
| Флаг | Поле | Описание |
|
||||
| ------------ | ----------------- | ------------------------- |
|
||||
| `-p, --port` | `Args.ServerPort` | Порт веб-сервера |
|
||||
| `--host` | `Args.ServerHost` | Хост привязки |
|
||||
| `--check` | `Args.NeedCheck` | Включить фоновую проверку |
|
||||
|
||||
### Глобальные (`cmd/root.go`)
|
||||
|
||||
| Флаг | Поле | Описание |
|
||||
| --------------- | ----------------- | ----------------- |
|
||||
| `--config` | `Args.ConfigPath` | Путь к config.yml |
|
||||
| `-v, --verbose` | `Args.Verbose` | Подробный лог |
|
||||
|
||||
## Конфигурация
|
||||
|
||||
Подробное описание параметров — в разделе [config.yml](../../common/config/config.md).
|
||||
|
||||
Приоритет: Defaults < `config.yml` < Env < CLI-флаги.
|
||||
|
||||
CLI-флаги переопределяют конфигурацию только если переданы явно (`cmd.Flags().Changed()`).
|
||||
Для этого в Cobra используются zero-value defaults (0, "", false), чтобы отличить «не передан» от «передан со значением по умолчанию».
|
||||
|
||||
## Шаблоны
|
||||
|
||||
HTML-шаблоны встроены через `//go:embed`:
|
||||
|
||||
- `base.html` — общий каркас (header, footer);
|
||||
- `list.html` — список плейлистов с пагинацией;
|
||||
- `details.html` — детали плейлиста и список каналов;
|
||||
- `notfound.html` — страница 404.
|
||||
|
||||
SVG-логотипы каналов передаются через `encodeURIComponent` в data-URI для корректной работы с кавычками в HTML.
|
||||
|
||||
При отсутствии `playlists.ini` рендерится пустое состояние с alert-блоком.
|
||||
|
||||
## Кеширование
|
||||
|
||||
Два уровня кеша:
|
||||
|
||||
1. **Redis/KeyDB** (опционально) — постоянный кеш результатов проверки. TTL из `cache.ttl`.
|
||||
2. **In-memory** (`memCache`) — только при `serve --check`. Обновляется в реальном времени через callback. Не требует Redis.
|
||||
|
||||
In-memory кеш приоритетнее Redis при отображении в веб-интерфейсе.
|
||||
@@ -0,0 +1,59 @@
|
||||
---
|
||||
title: Компиляция
|
||||
icon: material/cog
|
||||
tags: ["iptvc", "сборка"]
|
||||
---
|
||||
|
||||
# Компиляция из исходного кода
|
||||
|
||||
Для компиляции потребуется [Go](https://go.dev/dl/) 1.23.6 и выше.
|
||||
|
||||
```bash
|
||||
git clone https://git.axenov.dev/IPTV/iptvc.git
|
||||
cd iptvc
|
||||
make linux
|
||||
# или make help для получения справки по рецептам
|
||||
```
|
||||
|
||||
## Доступные рецепты Makefile
|
||||
|
||||
| Команда | Назначение |
|
||||
| --- | --- |
|
||||
| `make linux` | Сборка под Linux (amd64 по умолчанию) |
|
||||
| `make win` | Сборка под Windows |
|
||||
| `make darwin` | Сборка под macOS |
|
||||
| `make release` | Сборка под все платформы (linux/windows/darwin × amd64/arm64) |
|
||||
| `make clean` | Удаление скомпилированных бинарников |
|
||||
| `make help` | Вывод списка доступных рецептов |
|
||||
|
||||
## Управление архитектурой
|
||||
|
||||
Архитектура целевой платформы задаётся переменной `GOARCH`:
|
||||
|
||||
```bash
|
||||
make darwin GOARCH=arm64 # macOS на Apple Silicon
|
||||
make linux GOARCH=arm64 # Linux ARM (Raspberry Pi и т.п.)
|
||||
```
|
||||
|
||||
## Результат
|
||||
|
||||
Скомпилированные бинарники и ZIP-архивы помещаются в директорию `bin/`:
|
||||
|
||||
```
|
||||
bin/
|
||||
├── linux_amd64/iptvc # или linux_arm64/
|
||||
├── linux_amd64.zip
|
||||
├── windows_amd64/iptvc.exe # или windows_arm64/
|
||||
├── windows_amd64.zip
|
||||
├── darwin_amd64/iptvc # или darwin_arm64/
|
||||
└── darwin_amd64.zip
|
||||
```
|
||||
|
||||
## Сборка без Make
|
||||
|
||||
Можно скомпилировать напрямую через `go build`:
|
||||
|
||||
```bash
|
||||
go build -o iptvc .
|
||||
go build -trimpath -ldflags="-s -w" -o iptvc .
|
||||
```
|
||||
@@ -0,0 +1,58 @@
|
||||
---
|
||||
title: Docker-образ
|
||||
icon: simple/docker
|
||||
tags: ["iptvc", "docker"]
|
||||
---
|
||||
|
||||
# Построение Docker-образа
|
||||
|
||||
## Сборка
|
||||
|
||||
Образ собирается из [Dockerfile](https://git.axenov.dev/IPTV/iptvc/src/branch/master/Dockerfile) — multi-stage сборка на базе `golang:1.25-alpine` с финальным образом `alpine:3.22`.
|
||||
|
||||
```bash
|
||||
docker build -t iptvc ./iptvc
|
||||
```
|
||||
|
||||
Можно передать версию через build-arg:
|
||||
|
||||
```bash
|
||||
docker build --build-arg IPTVC_VERSION=1.1.3 -t iptvc:v1.1.3 ./iptvc
|
||||
```
|
||||
|
||||
Целевая платформа и архитектура задаются через `GOOS` и `GOARCH`:
|
||||
|
||||
```bash
|
||||
docker build --build-arg GOOS=linux --build-arg GOARCH=arm64 -t iptvc:linux-arm64 ./iptvc
|
||||
```
|
||||
|
||||
## Запуск
|
||||
|
||||
```bash
|
||||
# Проверка плейлистов
|
||||
docker run --rm \
|
||||
-v ./playlists.ini:/app/playlists.ini \
|
||||
-v ./channels.json:/app/channels.json \
|
||||
iptvc check -i playlists.ini --repeat 0 --playlists-all-cooldown 60000
|
||||
|
||||
# Веб-сервер с фоновой проверкой
|
||||
docker run --rm -p 8080:8080 \
|
||||
-v ./playlists.ini:/app/playlists.ini \
|
||||
-v ./channels.json:/app/channels.json \
|
||||
iptvc serve -i playlists.ini -p 8080 --check
|
||||
```
|
||||
|
||||
## Использование в compose
|
||||
|
||||
В `compose.yml` сервиса `checker` образ собирается автоматически:
|
||||
|
||||
```yaml
|
||||
checker:
|
||||
image: git.axenov.dev/iptv/iptvc:latest
|
||||
build:
|
||||
context: ./iptvc
|
||||
dockerfile: Dockerfile
|
||||
command: ["check", "--repeat", "0", "--playlists-all-cooldown", "${CHECK_PLAYLISTS_ALL_COOLDOWN:-60000}"]
|
||||
```
|
||||
|
||||
Подробнее о полном окружении — в разделе [Развёртывание](../site/deploy.md).
|
||||
@@ -0,0 +1,103 @@
|
||||
---
|
||||
icon: material/book-cog-outline
|
||||
---
|
||||
|
||||
# :material-book-cog-outline: Сборка документации
|
||||
|
||||
## Стилистика и правила оформления
|
||||
|
||||
Все исходники хранятся в директории `content/` в формате **Markdown** (формат файлов `.md`).
|
||||
|
||||
Структура проекта и его конфигурация описываются в файле `mkdocs.yml` в корне репозитория.
|
||||
|
||||
Структура исходных файлов документации и содержание должны быть согласованными.
|
||||
|
||||
Все ссылки на соседние страницы и изображения должны быть относительными.
|
||||
|
||||
**Каждое предложение должно быть на одной строке.**
|
||||
Это даёт более наглядную разницу (diff) в тексте при работе с git.
|
||||
|
||||
Абзацы и списки должны отделяться 1 пустой строкой до и после.
|
||||
|
||||
Допустимо использовать любые стилистические возможности темы **Material for MkDocs** и самого **mkdocs**, но не следует визуально перегружать текст.
|
||||
Документацию по ним см. по ссылкам ниже.
|
||||
|
||||
## Добавление изображений
|
||||
|
||||
**Все изображения хранятся в директории `_assets/` рядом с документом.**
|
||||
|
||||
Общая суть такова:
|
||||
|
||||
* чем больше размеры, тем хуже должно быть качество;
|
||||
* чем меньше размеры, тем чётче должен быть текст.
|
||||
|
||||
Каждое изображение должно:
|
||||
|
||||
* быть сохранено в формате jpg;
|
||||
* иметь размер неболее 150 Кб;
|
||||
* быть сжатым с качеством 65-80% от исходного;
|
||||
* быть размером до 1500 px по наибольшей стороне.
|
||||
|
||||
Если на изображении есть текст, он должен оставаться различимым и читаемым.
|
||||
|
||||
Но если на изображении есть любые конфиденциальные данные и его невозможно кадрировать без потери смысла, то их необходимо скрыть.
|
||||
|
||||
Хорошей практикой будет использовать спойлеры для скрытия больших и/или идущих подряд нескольких изображений, например:
|
||||
|
||||
```
|
||||
Совершенно любой текст, lorem ipsum dolor sit amet.
|
||||
Совершенно любой текст, lorem ipsum dolor sit amet.
|
||||
|
||||
??? quote "В этом спойлере несколько больших картинок"
|
||||

|
||||

|
||||
|
||||
Продолжение текста, lorem ipsum dolor sit amet.
|
||||
Продолжение текста, lorem ipsum dolor sit amet.
|
||||
```
|
||||
|
||||
Эти простые правила позволят поддерживать репозиторий достаточно компактным, а страницы делать комфортными для чтения, экономя трафик для мобильных устройств.
|
||||
|
||||
## Стек
|
||||
|
||||
* make
|
||||
* [docker](https://docker.com)
|
||||
* [mkdocs](https://www.mkdocs.org/)
|
||||
* [squidfunk/mkdocs-material](https://hub.docker.com/r/squidfunk/mkdocs-material)
|
||||
* <https://squidfunk.github.io/mkdocs-material>
|
||||
* <https://squidfunk.github.io/mkdocs-material/reference/admonitions/>
|
||||
* <https://squidfunk.github.io/mkdocs-material/reference/icons-emojis/>
|
||||
|
||||
## Запуск mkdocs в контейнере
|
||||
|
||||
```
|
||||
make live
|
||||
```
|
||||
|
||||
Перегенерирует документацию на лету сразу после сохранения файлов.
|
||||
|
||||
Документацию в реальном времени можно просматривать по адресу [localhost:3000](http://localhost:3000).
|
||||
|
||||
## Генерация статического сайта
|
||||
|
||||
```
|
||||
make site
|
||||
```
|
||||
|
||||
Генерирует статические файлы, которую можно версионировать, хранить,деплоить отдельно или просматривать на ПК через браузер.
|
||||
|
||||
Готовый скомпилированный статический сайт с документацией находится в директории `site/`.
|
||||
|
||||
## Генерация docker-образа
|
||||
|
||||
```
|
||||
make image
|
||||
```
|
||||
|
||||
Собирает docker-образ на основе nginx, генерируя перед этим статический сайт.
|
||||
|
||||
Запустить контейнер из этого образа по адресу [localhost:3001](http://localhost:3001) можно командой:
|
||||
|
||||
```
|
||||
make run
|
||||
```
|
||||
@@ -0,0 +1,550 @@
|
||||
Информацию о лицензии см. на странице [Свободное ПО](../../../legal/license.md)
|
||||
|
||||
| Иконка | Код для вставки в текст | Код для вставки в frontmatter |
|
||||
| ------------------------------------------------ | -------------------------------------------------- | ------------------------------------------------ |
|
||||
| :vscode-account: | `:vscode-account:` | `vscode/account` |
|
||||
| :vscode-activate-breakpoints: | `:vscode-activate-breakpoints:` | `vscode/activate-breakpoints` |
|
||||
| :vscode-add: | `:vscode-add:` | `vscode/add` |
|
||||
| :vscode-add-small: | `:vscode-add-small:` | `vscode/add-small` |
|
||||
| :vscode-agent: | `:vscode-agent:` | `vscode/agent` |
|
||||
| :vscode-archive: | `:vscode-archive:` | `vscode/archive` |
|
||||
| :vscode-arrow-both: | `:vscode-arrow-both:` | `vscode/arrow-both` |
|
||||
| :vscode-arrow-circle-down: | `:vscode-arrow-circle-down:` | `vscode/arrow-circle-down` |
|
||||
| :vscode-arrow-circle-left: | `:vscode-arrow-circle-left:` | `vscode/arrow-circle-left` |
|
||||
| :vscode-arrow-circle-right: | `:vscode-arrow-circle-right:` | `vscode/arrow-circle-right` |
|
||||
| :vscode-arrow-circle-up: | `:vscode-arrow-circle-up:` | `vscode/arrow-circle-up` |
|
||||
| :vscode-arrow-down: | `:vscode-arrow-down:` | `vscode/arrow-down` |
|
||||
| :vscode-arrow-left: | `:vscode-arrow-left:` | `vscode/arrow-left` |
|
||||
| :vscode-arrow-right: | `:vscode-arrow-right:` | `vscode/arrow-right` |
|
||||
| :vscode-arrow-small-down: | `:vscode-arrow-small-down:` | `vscode/arrow-small-down` |
|
||||
| :vscode-arrow-small-left: | `:vscode-arrow-small-left:` | `vscode/arrow-small-left` |
|
||||
| :vscode-arrow-small-right: | `:vscode-arrow-small-right:` | `vscode/arrow-small-right` |
|
||||
| :vscode-arrow-small-up: | `:vscode-arrow-small-up:` | `vscode/arrow-small-up` |
|
||||
| :vscode-arrow-swap: | `:vscode-arrow-swap:` | `vscode/arrow-swap` |
|
||||
| :vscode-arrow-up: | `:vscode-arrow-up:` | `vscode/arrow-up` |
|
||||
| :vscode-ask: | `:vscode-ask:` | `vscode/ask` |
|
||||
| :vscode-attach: | `:vscode-attach:` | `vscode/attach` |
|
||||
| :vscode-azure: | `:vscode-azure:` | `vscode/azure` |
|
||||
| :vscode-azure-devops: | `:vscode-azure-devops:` | `vscode/azure-devops` |
|
||||
| :vscode-beaker: | `:vscode-beaker:` | `vscode/beaker` |
|
||||
| :vscode-beaker-stop: | `:vscode-beaker-stop:` | `vscode/beaker-stop` |
|
||||
| :vscode-bell: | `:vscode-bell:` | `vscode/bell` |
|
||||
| :vscode-bell-dot: | `:vscode-bell-dot:` | `vscode/bell-dot` |
|
||||
| :vscode-bell-slash: | `:vscode-bell-slash:` | `vscode/bell-slash` |
|
||||
| :vscode-bell-slash-dot: | `:vscode-bell-slash-dot:` | `vscode/bell-slash-dot` |
|
||||
| :vscode-blank: | `:vscode-blank:` | `vscode/blank` |
|
||||
| :vscode-bold: | `:vscode-bold:` | `vscode/bold` |
|
||||
| :vscode-book: | `:vscode-book:` | `vscode/book` |
|
||||
| :vscode-bookmark: | `:vscode-bookmark:` | `vscode/bookmark` |
|
||||
| :vscode-bracket-dot: | `:vscode-bracket-dot:` | `vscode/bracket-dot` |
|
||||
| :vscode-bracket-error: | `:vscode-bracket-error:` | `vscode/bracket-error` |
|
||||
| :vscode-briefcase: | `:vscode-briefcase:` | `vscode/briefcase` |
|
||||
| :vscode-broadcast: | `:vscode-broadcast:` | `vscode/broadcast` |
|
||||
| :vscode-browser: | `:vscode-browser:` | `vscode/browser` |
|
||||
| :vscode-bug: | `:vscode-bug:` | `vscode/bug` |
|
||||
| :vscode-build: | `:vscode-build:` | `vscode/build` |
|
||||
| :vscode-calendar: | `:vscode-calendar:` | `vscode/calendar` |
|
||||
| :vscode-call-incoming: | `:vscode-call-incoming:` | `vscode/call-incoming` |
|
||||
| :vscode-call-outgoing: | `:vscode-call-outgoing:` | `vscode/call-outgoing` |
|
||||
| :vscode-case-sensitive: | `:vscode-case-sensitive:` | `vscode/case-sensitive` |
|
||||
| :vscode-chat-export: | `:vscode-chat-export:` | `vscode/chat-export` |
|
||||
| :vscode-chat-import: | `:vscode-chat-import:` | `vscode/chat-import` |
|
||||
| :vscode-chat-sparkle: | `:vscode-chat-sparkle:` | `vscode/chat-sparkle` |
|
||||
| :vscode-chat-sparkle-error: | `:vscode-chat-sparkle-error:` | `vscode/chat-sparkle-error` |
|
||||
| :vscode-chat-sparkle-warning: | `:vscode-chat-sparkle-warning:` | `vscode/chat-sparkle-warning` |
|
||||
| :vscode-check: | `:vscode-check:` | `vscode/check` |
|
||||
| :vscode-check-all: | `:vscode-check-all:` | `vscode/check-all` |
|
||||
| :vscode-checklist: | `:vscode-checklist:` | `vscode/checklist` |
|
||||
| :vscode-chevron-down: | `:vscode-chevron-down:` | `vscode/chevron-down` |
|
||||
| :vscode-chevron-left: | `:vscode-chevron-left:` | `vscode/chevron-left` |
|
||||
| :vscode-chevron-right: | `:vscode-chevron-right:` | `vscode/chevron-right` |
|
||||
| :vscode-chevron-up: | `:vscode-chevron-up:` | `vscode/chevron-up` |
|
||||
| :vscode-chip: | `:vscode-chip:` | `vscode/chip` |
|
||||
| :vscode-chrome-close: | `:vscode-chrome-close:` | `vscode/chrome-close` |
|
||||
| :vscode-chrome-maximize: | `:vscode-chrome-maximize:` | `vscode/chrome-maximize` |
|
||||
| :vscode-chrome-minimize: | `:vscode-chrome-minimize:` | `vscode/chrome-minimize` |
|
||||
| :vscode-chrome-restore: | `:vscode-chrome-restore:` | `vscode/chrome-restore` |
|
||||
| :vscode-circle: | `:vscode-circle:` | `vscode/circle` |
|
||||
| :vscode-circle-filled: | `:vscode-circle-filled:` | `vscode/circle-filled` |
|
||||
| :vscode-circle-large: | `:vscode-circle-large:` | `vscode/circle-large` |
|
||||
| :vscode-circle-large-filled: | `:vscode-circle-large-filled:` | `vscode/circle-large-filled` |
|
||||
| :vscode-circle-slash: | `:vscode-circle-slash:` | `vscode/circle-slash` |
|
||||
| :vscode-circle-small: | `:vscode-circle-small:` | `vscode/circle-small` |
|
||||
| :vscode-circle-small-filled: | `:vscode-circle-small-filled:` | `vscode/circle-small-filled` |
|
||||
| :vscode-circuit-board: | `:vscode-circuit-board:` | `vscode/circuit-board` |
|
||||
| :vscode-claude: | `:vscode-claude:` | `vscode/claude` |
|
||||
| :vscode-clear-all: | `:vscode-clear-all:` | `vscode/clear-all` |
|
||||
| :vscode-clippy: | `:vscode-clippy:` | `vscode/clippy` |
|
||||
| :vscode-clockface: | `:vscode-clockface:` | `vscode/clockface` |
|
||||
| :vscode-close: | `:vscode-close:` | `vscode/close` |
|
||||
| :vscode-close-all: | `:vscode-close-all:` | `vscode/close-all` |
|
||||
| :vscode-cloud: | `:vscode-cloud:` | `vscode/cloud` |
|
||||
| :vscode-cloud-download: | `:vscode-cloud-download:` | `vscode/cloud-download` |
|
||||
| :vscode-cloud-small: | `:vscode-cloud-small:` | `vscode/cloud-small` |
|
||||
| :vscode-cloud-upload: | `:vscode-cloud-upload:` | `vscode/cloud-upload` |
|
||||
| :vscode-code: | `:vscode-code:` | `vscode/code` |
|
||||
| :vscode-code-oss: | `:vscode-code-oss:` | `vscode/code-oss` |
|
||||
| :vscode-code-review: | `:vscode-code-review:` | `vscode/code-review` |
|
||||
| :vscode-coffee: | `:vscode-coffee:` | `vscode/coffee` |
|
||||
| :vscode-collapse-all: | `:vscode-collapse-all:` | `vscode/collapse-all` |
|
||||
| :vscode-collection: | `:vscode-collection:` | `vscode/collection` |
|
||||
| :vscode-collection-small: | `:vscode-collection-small:` | `vscode/collection-small` |
|
||||
| :vscode-color-mode: | `:vscode-color-mode:` | `vscode/color-mode` |
|
||||
| :vscode-combine: | `:vscode-combine:` | `vscode/combine` |
|
||||
| :vscode-comment: | `:vscode-comment:` | `vscode/comment` |
|
||||
| :vscode-comment-discussion: | `:vscode-comment-discussion:` | `vscode/comment-discussion` |
|
||||
| :vscode-comment-discussion-quote: | `:vscode-comment-discussion-quote:` | `vscode/comment-discussion-quote` |
|
||||
| :vscode-comment-discussion-sparkle: | `:vscode-comment-discussion-sparkle:` | `vscode/comment-discussion-sparkle` |
|
||||
| :vscode-comment-draft: | `:vscode-comment-draft:` | `vscode/comment-draft` |
|
||||
| :vscode-comment-unresolved: | `:vscode-comment-unresolved:` | `vscode/comment-unresolved` |
|
||||
| :vscode-compass: | `:vscode-compass:` | `vscode/compass` |
|
||||
| :vscode-compass-active: | `:vscode-compass-active:` | `vscode/compass-active` |
|
||||
| :vscode-compass-dot: | `:vscode-compass-dot:` | `vscode/compass-dot` |
|
||||
| :vscode-copilot: | `:vscode-copilot:` | `vscode/copilot` |
|
||||
| :vscode-copilot-blocked: | `:vscode-copilot-blocked:` | `vscode/copilot-blocked` |
|
||||
| :vscode-copilot-error: | `:vscode-copilot-error:` | `vscode/copilot-error` |
|
||||
| :vscode-copilot-in-progress: | `:vscode-copilot-in-progress:` | `vscode/copilot-in-progress` |
|
||||
| :vscode-copilot-large: | `:vscode-copilot-large:` | `vscode/copilot-large` |
|
||||
| :vscode-copilot-not-connected: | `:vscode-copilot-not-connected:` | `vscode/copilot-not-connected` |
|
||||
| :vscode-copilot-snooze: | `:vscode-copilot-snooze:` | `vscode/copilot-snooze` |
|
||||
| :vscode-copilot-success: | `:vscode-copilot-success:` | `vscode/copilot-success` |
|
||||
| :vscode-copilot-unavailable: | `:vscode-copilot-unavailable:` | `vscode/copilot-unavailable` |
|
||||
| :vscode-copilot-warning: | `:vscode-copilot-warning:` | `vscode/copilot-warning` |
|
||||
| :vscode-copilot-warning-large: | `:vscode-copilot-warning-large:` | `vscode/copilot-warning-large` |
|
||||
| :vscode-copy: | `:vscode-copy:` | `vscode/copy` |
|
||||
| :vscode-coverage: | `:vscode-coverage:` | `vscode/coverage` |
|
||||
| :vscode-credit-card: | `:vscode-credit-card:` | `vscode/credit-card` |
|
||||
| :vscode-cursor: | `:vscode-cursor:` | `vscode/cursor` |
|
||||
| :vscode-dash: | `:vscode-dash:` | `vscode/dash` |
|
||||
| :vscode-dashboard: | `:vscode-dashboard:` | `vscode/dashboard` |
|
||||
| :vscode-database: | `:vscode-database:` | `vscode/database` |
|
||||
| :vscode-debug: | `:vscode-debug:` | `vscode/debug` |
|
||||
| :vscode-debug-all: | `:vscode-debug-all:` | `vscode/debug-all` |
|
||||
| :vscode-debug-alt: | `:vscode-debug-alt:` | `vscode/debug-alt` |
|
||||
| :vscode-debug-alt-small: | `:vscode-debug-alt-small:` | `vscode/debug-alt-small` |
|
||||
| :vscode-debug-breakpoint-conditional: | `:vscode-debug-breakpoint-conditional:` | `vscode/debug-breakpoint-conditional` |
|
||||
| :vscode-debug-breakpoint-conditional-unverified: | `:vscode-debug-breakpoint-conditional-unverified:` | `vscode/debug-breakpoint-conditional-unverified` |
|
||||
| :vscode-debug-breakpoint-data: | `:vscode-debug-breakpoint-data:` | `vscode/debug-breakpoint-data` |
|
||||
| :vscode-debug-breakpoint-data-unverified: | `:vscode-debug-breakpoint-data-unverified:` | `vscode/debug-breakpoint-data-unverified` |
|
||||
| :vscode-debug-breakpoint-function: | `:vscode-debug-breakpoint-function:` | `vscode/debug-breakpoint-function` |
|
||||
| :vscode-debug-breakpoint-function-unverified: | `:vscode-debug-breakpoint-function-unverified:` | `vscode/debug-breakpoint-function-unverified` |
|
||||
| :vscode-debug-breakpoint-log: | `:vscode-debug-breakpoint-log:` | `vscode/debug-breakpoint-log` |
|
||||
| :vscode-debug-breakpoint-log-unverified: | `:vscode-debug-breakpoint-log-unverified:` | `vscode/debug-breakpoint-log-unverified` |
|
||||
| :vscode-debug-breakpoint-unsupported: | `:vscode-debug-breakpoint-unsupported:` | `vscode/debug-breakpoint-unsupported` |
|
||||
| :vscode-debug-connected: | `:vscode-debug-connected:` | `vscode/debug-connected` |
|
||||
| :vscode-debug-console: | `:vscode-debug-console:` | `vscode/debug-console` |
|
||||
| :vscode-debug-continue: | `:vscode-debug-continue:` | `vscode/debug-continue` |
|
||||
| :vscode-debug-continue-small: | `:vscode-debug-continue-small:` | `vscode/debug-continue-small` |
|
||||
| :vscode-debug-coverage: | `:vscode-debug-coverage:` | `vscode/debug-coverage` |
|
||||
| :vscode-debug-disconnect: | `:vscode-debug-disconnect:` | `vscode/debug-disconnect` |
|
||||
| :vscode-debug-line-by-line: | `:vscode-debug-line-by-line:` | `vscode/debug-line-by-line` |
|
||||
| :vscode-debug-pause: | `:vscode-debug-pause:` | `vscode/debug-pause` |
|
||||
| :vscode-debug-rerun: | `:vscode-debug-rerun:` | `vscode/debug-rerun` |
|
||||
| :vscode-debug-restart: | `:vscode-debug-restart:` | `vscode/debug-restart` |
|
||||
| :vscode-debug-restart-frame: | `:vscode-debug-restart-frame:` | `vscode/debug-restart-frame` |
|
||||
| :vscode-debug-reverse-continue: | `:vscode-debug-reverse-continue:` | `vscode/debug-reverse-continue` |
|
||||
| :vscode-debug-stackframe: | `:vscode-debug-stackframe:` | `vscode/debug-stackframe` |
|
||||
| :vscode-debug-stackframe-active: | `:vscode-debug-stackframe-active:` | `vscode/debug-stackframe-active` |
|
||||
| :vscode-debug-start: | `:vscode-debug-start:` | `vscode/debug-start` |
|
||||
| :vscode-debug-step-back: | `:vscode-debug-step-back:` | `vscode/debug-step-back` |
|
||||
| :vscode-debug-step-into: | `:vscode-debug-step-into:` | `vscode/debug-step-into` |
|
||||
| :vscode-debug-step-out: | `:vscode-debug-step-out:` | `vscode/debug-step-out` |
|
||||
| :vscode-debug-step-over: | `:vscode-debug-step-over:` | `vscode/debug-step-over` |
|
||||
| :vscode-debug-stop: | `:vscode-debug-stop:` | `vscode/debug-stop` |
|
||||
| :vscode-desktop-download: | `:vscode-desktop-download:` | `vscode/desktop-download` |
|
||||
| :vscode-device-camera: | `:vscode-device-camera:` | `vscode/device-camera` |
|
||||
| :vscode-device-camera-video: | `:vscode-device-camera-video:` | `vscode/device-camera-video` |
|
||||
| :vscode-device-mobile: | `:vscode-device-mobile:` | `vscode/device-mobile` |
|
||||
| :vscode-diff: | `:vscode-diff:` | `vscode/diff` |
|
||||
| :vscode-diff-added: | `:vscode-diff-added:` | `vscode/diff-added` |
|
||||
| :vscode-diff-ignored: | `:vscode-diff-ignored:` | `vscode/diff-ignored` |
|
||||
| :vscode-diff-modified: | `:vscode-diff-modified:` | `vscode/diff-modified` |
|
||||
| :vscode-diff-multiple: | `:vscode-diff-multiple:` | `vscode/diff-multiple` |
|
||||
| :vscode-diff-removed: | `:vscode-diff-removed:` | `vscode/diff-removed` |
|
||||
| :vscode-diff-renamed: | `:vscode-diff-renamed:` | `vscode/diff-renamed` |
|
||||
| :vscode-diff-single: | `:vscode-diff-single:` | `vscode/diff-single` |
|
||||
| :vscode-discard: | `:vscode-discard:` | `vscode/discard` |
|
||||
| :vscode-download: | `:vscode-download:` | `vscode/download` |
|
||||
| :vscode-edit: | `:vscode-edit:` | `vscode/edit` |
|
||||
| :vscode-edit-code: | `:vscode-edit-code:` | `vscode/edit-code` |
|
||||
| :vscode-edit-session: | `:vscode-edit-session:` | `vscode/edit-session` |
|
||||
| :vscode-edit-sparkle: | `:vscode-edit-sparkle:` | `vscode/edit-sparkle` |
|
||||
| :vscode-editor-layout: | `:vscode-editor-layout:` | `vscode/editor-layout` |
|
||||
| :vscode-ellipsis: | `:vscode-ellipsis:` | `vscode/ellipsis` |
|
||||
| :vscode-empty-window: | `:vscode-empty-window:` | `vscode/empty-window` |
|
||||
| :vscode-eraser: | `:vscode-eraser:` | `vscode/eraser` |
|
||||
| :vscode-error: | `:vscode-error:` | `vscode/error` |
|
||||
| :vscode-error-small: | `:vscode-error-small:` | `vscode/error-small` |
|
||||
| :vscode-exclude: | `:vscode-exclude:` | `vscode/exclude` |
|
||||
| :vscode-expand-all: | `:vscode-expand-all:` | `vscode/expand-all` |
|
||||
| :vscode-export: | `:vscode-export:` | `vscode/export` |
|
||||
| :vscode-extensions: | `:vscode-extensions:` | `vscode/extensions` |
|
||||
| :vscode-extensions-large: | `:vscode-extensions-large:` | `vscode/extensions-large` |
|
||||
| :vscode-eye: | `:vscode-eye:` | `vscode/eye` |
|
||||
| :vscode-eye-closed: | `:vscode-eye-closed:` | `vscode/eye-closed` |
|
||||
| :vscode-feedback: | `:vscode-feedback:` | `vscode/feedback` |
|
||||
| :vscode-file: | `:vscode-file:` | `vscode/file` |
|
||||
| :vscode-file-binary: | `:vscode-file-binary:` | `vscode/file-binary` |
|
||||
| :vscode-file-code: | `:vscode-file-code:` | `vscode/file-code` |
|
||||
| :vscode-file-media: | `:vscode-file-media:` | `vscode/file-media` |
|
||||
| :vscode-file-pdf: | `:vscode-file-pdf:` | `vscode/file-pdf` |
|
||||
| :vscode-file-submodule: | `:vscode-file-submodule:` | `vscode/file-submodule` |
|
||||
| :vscode-file-symlink-directory: | `:vscode-file-symlink-directory:` | `vscode/file-symlink-directory` |
|
||||
| :vscode-file-symlink-file: | `:vscode-file-symlink-file:` | `vscode/file-symlink-file` |
|
||||
| :vscode-file-text: | `:vscode-file-text:` | `vscode/file-text` |
|
||||
| :vscode-file-zip: | `:vscode-file-zip:` | `vscode/file-zip` |
|
||||
| :vscode-files: | `:vscode-files:` | `vscode/files` |
|
||||
| :vscode-filter: | `:vscode-filter:` | `vscode/filter` |
|
||||
| :vscode-filter-filled: | `:vscode-filter-filled:` | `vscode/filter-filled` |
|
||||
| :vscode-flag: | `:vscode-flag:` | `vscode/flag` |
|
||||
| :vscode-flame: | `:vscode-flame:` | `vscode/flame` |
|
||||
| :vscode-fold: | `:vscode-fold:` | `vscode/fold` |
|
||||
| :vscode-fold-down: | `:vscode-fold-down:` | `vscode/fold-down` |
|
||||
| :vscode-fold-up: | `:vscode-fold-up:` | `vscode/fold-up` |
|
||||
| :vscode-folder: | `:vscode-folder:` | `vscode/folder` |
|
||||
| :vscode-folder-active: | `:vscode-folder-active:` | `vscode/folder-active` |
|
||||
| :vscode-folder-library: | `:vscode-folder-library:` | `vscode/folder-library` |
|
||||
| :vscode-folder-opened: | `:vscode-folder-opened:` | `vscode/folder-opened` |
|
||||
| :vscode-forward: | `:vscode-forward:` | `vscode/forward` |
|
||||
| :vscode-game: | `:vscode-game:` | `vscode/game` |
|
||||
| :vscode-gear: | `:vscode-gear:` | `vscode/gear` |
|
||||
| :vscode-gift: | `:vscode-gift:` | `vscode/gift` |
|
||||
| :vscode-gist: | `:vscode-gist:` | `vscode/gist` |
|
||||
| :vscode-gist-secret: | `:vscode-gist-secret:` | `vscode/gist-secret` |
|
||||
| :vscode-git-branch: | `:vscode-git-branch:` | `vscode/git-branch` |
|
||||
| :vscode-git-branch-changes: | `:vscode-git-branch-changes:` | `vscode/git-branch-changes` |
|
||||
| :vscode-git-branch-conflicts: | `:vscode-git-branch-conflicts:` | `vscode/git-branch-conflicts` |
|
||||
| :vscode-git-branch-staged-changes: | `:vscode-git-branch-staged-changes:` | `vscode/git-branch-staged-changes` |
|
||||
| :vscode-git-commit: | `:vscode-git-commit:` | `vscode/git-commit` |
|
||||
| :vscode-git-compare: | `:vscode-git-compare:` | `vscode/git-compare` |
|
||||
| :vscode-git-fetch: | `:vscode-git-fetch:` | `vscode/git-fetch` |
|
||||
| :vscode-git-merge: | `:vscode-git-merge:` | `vscode/git-merge` |
|
||||
| :vscode-git-pull-request: | `:vscode-git-pull-request:` | `vscode/git-pull-request` |
|
||||
| :vscode-git-pull-request-closed: | `:vscode-git-pull-request-closed:` | `vscode/git-pull-request-closed` |
|
||||
| :vscode-git-pull-request-create: | `:vscode-git-pull-request-create:` | `vscode/git-pull-request-create` |
|
||||
| :vscode-git-pull-request-done: | `:vscode-git-pull-request-done:` | `vscode/git-pull-request-done` |
|
||||
| :vscode-git-pull-request-draft: | `:vscode-git-pull-request-draft:` | `vscode/git-pull-request-draft` |
|
||||
| :vscode-git-pull-request-go-to-changes: | `:vscode-git-pull-request-go-to-changes:` | `vscode/git-pull-request-go-to-changes` |
|
||||
| :vscode-git-pull-request-new-changes: | `:vscode-git-pull-request-new-changes:` | `vscode/git-pull-request-new-changes` |
|
||||
| :vscode-git-stash: | `:vscode-git-stash:` | `vscode/git-stash` |
|
||||
| :vscode-git-stash-apply: | `:vscode-git-stash-apply:` | `vscode/git-stash-apply` |
|
||||
| :vscode-git-stash-pop: | `:vscode-git-stash-pop:` | `vscode/git-stash-pop` |
|
||||
| :vscode-github: | `:vscode-github:` | `vscode/github` |
|
||||
| :vscode-github-action: | `:vscode-github-action:` | `vscode/github-action` |
|
||||
| :vscode-github-alt: | `:vscode-github-alt:` | `vscode/github-alt` |
|
||||
| :vscode-github-inverted: | `:vscode-github-inverted:` | `vscode/github-inverted` |
|
||||
| :vscode-github-project: | `:vscode-github-project:` | `vscode/github-project` |
|
||||
| :vscode-globe: | `:vscode-globe:` | `vscode/globe` |
|
||||
| :vscode-go-to-editing-session: | `:vscode-go-to-editing-session:` | `vscode/go-to-editing-session` |
|
||||
| :vscode-go-to-file: | `:vscode-go-to-file:` | `vscode/go-to-file` |
|
||||
| :vscode-go-to-search: | `:vscode-go-to-search:` | `vscode/go-to-search` |
|
||||
| :vscode-grabber: | `:vscode-grabber:` | `vscode/grabber` |
|
||||
| :vscode-graph: | `:vscode-graph:` | `vscode/graph` |
|
||||
| :vscode-graph-left: | `:vscode-graph-left:` | `vscode/graph-left` |
|
||||
| :vscode-graph-line: | `:vscode-graph-line:` | `vscode/graph-line` |
|
||||
| :vscode-graph-scatter: | `:vscode-graph-scatter:` | `vscode/graph-scatter` |
|
||||
| :vscode-gripper: | `:vscode-gripper:` | `vscode/gripper` |
|
||||
| :vscode-group-by-ref-type: | `:vscode-group-by-ref-type:` | `vscode/group-by-ref-type` |
|
||||
| :vscode-heart: | `:vscode-heart:` | `vscode/heart` |
|
||||
| :vscode-heart-filled: | `:vscode-heart-filled:` | `vscode/heart-filled` |
|
||||
| :vscode-history: | `:vscode-history:` | `vscode/history` |
|
||||
| :vscode-home: | `:vscode-home:` | `vscode/home` |
|
||||
| :vscode-horizontal-rule: | `:vscode-horizontal-rule:` | `vscode/horizontal-rule` |
|
||||
| :vscode-hubot: | `:vscode-hubot:` | `vscode/hubot` |
|
||||
| :vscode-inbox: | `:vscode-inbox:` | `vscode/inbox` |
|
||||
| :vscode-indent: | `:vscode-indent:` | `vscode/indent` |
|
||||
| :vscode-index-zero: | `:vscode-index-zero:` | `vscode/index-zero` |
|
||||
| :vscode-info: | `:vscode-info:` | `vscode/info` |
|
||||
| :vscode-insert: | `:vscode-insert:` | `vscode/insert` |
|
||||
| :vscode-inspect: | `:vscode-inspect:` | `vscode/inspect` |
|
||||
| :vscode-issue-draft: | `:vscode-issue-draft:` | `vscode/issue-draft` |
|
||||
| :vscode-issue-reopened: | `:vscode-issue-reopened:` | `vscode/issue-reopened` |
|
||||
| :vscode-issues: | `:vscode-issues:` | `vscode/issues` |
|
||||
| :vscode-italic: | `:vscode-italic:` | `vscode/italic` |
|
||||
| :vscode-jersey: | `:vscode-jersey:` | `vscode/jersey` |
|
||||
| :vscode-json: | `:vscode-json:` | `vscode/json` |
|
||||
| :vscode-kebab-vertical: | `:vscode-kebab-vertical:` | `vscode/kebab-vertical` |
|
||||
| :vscode-key: | `:vscode-key:` | `vscode/key` |
|
||||
| :vscode-keyboard-tab: | `:vscode-keyboard-tab:` | `vscode/keyboard-tab` |
|
||||
| :vscode-keyboard-tab-above: | `:vscode-keyboard-tab-above:` | `vscode/keyboard-tab-above` |
|
||||
| :vscode-keyboard-tab-below: | `:vscode-keyboard-tab-below:` | `vscode/keyboard-tab-below` |
|
||||
| :vscode-law: | `:vscode-law:` | `vscode/law` |
|
||||
| :vscode-layers: | `:vscode-layers:` | `vscode/layers` |
|
||||
| :vscode-layers-active: | `:vscode-layers-active:` | `vscode/layers-active` |
|
||||
| :vscode-layers-dot: | `:vscode-layers-dot:` | `vscode/layers-dot` |
|
||||
| :vscode-layout: | `:vscode-layout:` | `vscode/layout` |
|
||||
| :vscode-layout-activitybar-left: | `:vscode-layout-activitybar-left:` | `vscode/layout-activitybar-left` |
|
||||
| :vscode-layout-activitybar-right: | `:vscode-layout-activitybar-right:` | `vscode/layout-activitybar-right` |
|
||||
| :vscode-layout-centered: | `:vscode-layout-centered:` | `vscode/layout-centered` |
|
||||
| :vscode-layout-menubar: | `:vscode-layout-menubar:` | `vscode/layout-menubar` |
|
||||
| :vscode-layout-panel: | `:vscode-layout-panel:` | `vscode/layout-panel` |
|
||||
| :vscode-layout-panel-center: | `:vscode-layout-panel-center:` | `vscode/layout-panel-center` |
|
||||
| :vscode-layout-panel-dock: | `:vscode-layout-panel-dock:` | `vscode/layout-panel-dock` |
|
||||
| :vscode-layout-panel-justify: | `:vscode-layout-panel-justify:` | `vscode/layout-panel-justify` |
|
||||
| :vscode-layout-panel-left: | `:vscode-layout-panel-left:` | `vscode/layout-panel-left` |
|
||||
| :vscode-layout-panel-off: | `:vscode-layout-panel-off:` | `vscode/layout-panel-off` |
|
||||
| :vscode-layout-panel-right: | `:vscode-layout-panel-right:` | `vscode/layout-panel-right` |
|
||||
| :vscode-layout-sidebar-left: | `:vscode-layout-sidebar-left:` | `vscode/layout-sidebar-left` |
|
||||
| :vscode-layout-sidebar-left-dock: | `:vscode-layout-sidebar-left-dock:` | `vscode/layout-sidebar-left-dock` |
|
||||
| :vscode-layout-sidebar-left-off: | `:vscode-layout-sidebar-left-off:` | `vscode/layout-sidebar-left-off` |
|
||||
| :vscode-layout-sidebar-right: | `:vscode-layout-sidebar-right:` | `vscode/layout-sidebar-right` |
|
||||
| :vscode-layout-sidebar-right-dock: | `:vscode-layout-sidebar-right-dock:` | `vscode/layout-sidebar-right-dock` |
|
||||
| :vscode-layout-sidebar-right-off: | `:vscode-layout-sidebar-right-off:` | `vscode/layout-sidebar-right-off` |
|
||||
| :vscode-layout-statusbar: | `:vscode-layout-statusbar:` | `vscode/layout-statusbar` |
|
||||
| :vscode-library: | `:vscode-library:` | `vscode/library` |
|
||||
| :vscode-lightbulb: | `:vscode-lightbulb:` | `vscode/lightbulb` |
|
||||
| :vscode-lightbulb-autofix: | `:vscode-lightbulb-autofix:` | `vscode/lightbulb-autofix` |
|
||||
| :vscode-lightbulb-empty: | `:vscode-lightbulb-empty:` | `vscode/lightbulb-empty` |
|
||||
| :vscode-lightbulb-sparkle: | `:vscode-lightbulb-sparkle:` | `vscode/lightbulb-sparkle` |
|
||||
| :vscode-link: | `:vscode-link:` | `vscode/link` |
|
||||
| :vscode-link-external: | `:vscode-link-external:` | `vscode/link-external` |
|
||||
| :vscode-list-filter: | `:vscode-list-filter:` | `vscode/list-filter` |
|
||||
| :vscode-list-flat: | `:vscode-list-flat:` | `vscode/list-flat` |
|
||||
| :vscode-list-ordered: | `:vscode-list-ordered:` | `vscode/list-ordered` |
|
||||
| :vscode-list-selection: | `:vscode-list-selection:` | `vscode/list-selection` |
|
||||
| :vscode-list-tree: | `:vscode-list-tree:` | `vscode/list-tree` |
|
||||
| :vscode-list-unordered: | `:vscode-list-unordered:` | `vscode/list-unordered` |
|
||||
| :vscode-live-share: | `:vscode-live-share:` | `vscode/live-share` |
|
||||
| :vscode-loading: | `:vscode-loading:` | `vscode/loading` |
|
||||
| :vscode-location: | `:vscode-location:` | `vscode/location` |
|
||||
| :vscode-lock: | `:vscode-lock:` | `vscode/lock` |
|
||||
| :vscode-lock-small: | `:vscode-lock-small:` | `vscode/lock-small` |
|
||||
| :vscode-magnet: | `:vscode-magnet:` | `vscode/magnet` |
|
||||
| :vscode-mail: | `:vscode-mail:` | `vscode/mail` |
|
||||
| :vscode-mail-read: | `:vscode-mail-read:` | `vscode/mail-read` |
|
||||
| :vscode-map: | `:vscode-map:` | `vscode/map` |
|
||||
| :vscode-map-filled: | `:vscode-map-filled:` | `vscode/map-filled` |
|
||||
| :vscode-map-vertical: | `:vscode-map-vertical:` | `vscode/map-vertical` |
|
||||
| :vscode-map-vertical-filled: | `:vscode-map-vertical-filled:` | `vscode/map-vertical-filled` |
|
||||
| :vscode-markdown: | `:vscode-markdown:` | `vscode/markdown` |
|
||||
| :vscode-mcp: | `:vscode-mcp:` | `vscode/mcp` |
|
||||
| :vscode-megaphone: | `:vscode-megaphone:` | `vscode/megaphone` |
|
||||
| :vscode-mention: | `:vscode-mention:` | `vscode/mention` |
|
||||
| :vscode-menu: | `:vscode-menu:` | `vscode/menu` |
|
||||
| :vscode-merge: | `:vscode-merge:` | `vscode/merge` |
|
||||
| :vscode-merge-into: | `:vscode-merge-into:` | `vscode/merge-into` |
|
||||
| :vscode-mic: | `:vscode-mic:` | `vscode/mic` |
|
||||
| :vscode-mic-filled: | `:vscode-mic-filled:` | `vscode/mic-filled` |
|
||||
| :vscode-milestone: | `:vscode-milestone:` | `vscode/milestone` |
|
||||
| :vscode-mirror: | `:vscode-mirror:` | `vscode/mirror` |
|
||||
| :vscode-mortar-board: | `:vscode-mortar-board:` | `vscode/mortar-board` |
|
||||
| :vscode-move: | `:vscode-move:` | `vscode/move` |
|
||||
| :vscode-multiple-windows: | `:vscode-multiple-windows:` | `vscode/multiple-windows` |
|
||||
| :vscode-music: | `:vscode-music:` | `vscode/music` |
|
||||
| :vscode-mute: | `:vscode-mute:` | `vscode/mute` |
|
||||
| :vscode-new-collection: | `:vscode-new-collection:` | `vscode/new-collection` |
|
||||
| :vscode-new-file: | `:vscode-new-file:` | `vscode/new-file` |
|
||||
| :vscode-new-folder: | `:vscode-new-folder:` | `vscode/new-folder` |
|
||||
| :vscode-new-session: | `:vscode-new-session:` | `vscode/new-session` |
|
||||
| :vscode-newline: | `:vscode-newline:` | `vscode/newline` |
|
||||
| :vscode-no-newline: | `:vscode-no-newline:` | `vscode/no-newline` |
|
||||
| :vscode-note: | `:vscode-note:` | `vscode/note` |
|
||||
| :vscode-notebook: | `:vscode-notebook:` | `vscode/notebook` |
|
||||
| :vscode-notebook-template: | `:vscode-notebook-template:` | `vscode/notebook-template` |
|
||||
| :vscode-octoface: | `:vscode-octoface:` | `vscode/octoface` |
|
||||
| :vscode-open-in-product: | `:vscode-open-in-product:` | `vscode/open-in-product` |
|
||||
| :vscode-open-in-window: | `:vscode-open-in-window:` | `vscode/open-in-window` |
|
||||
| :vscode-open-preview: | `:vscode-open-preview:` | `vscode/open-preview` |
|
||||
| :vscode-openai: | `:vscode-openai:` | `vscode/openai` |
|
||||
| :vscode-organization: | `:vscode-organization:` | `vscode/organization` |
|
||||
| :vscode-output: | `:vscode-output:` | `vscode/output` |
|
||||
| :vscode-package: | `:vscode-package:` | `vscode/package` |
|
||||
| :vscode-paintcan: | `:vscode-paintcan:` | `vscode/paintcan` |
|
||||
| :vscode-pass: | `:vscode-pass:` | `vscode/pass` |
|
||||
| :vscode-pass-filled: | `:vscode-pass-filled:` | `vscode/pass-filled` |
|
||||
| :vscode-percentage: | `:vscode-percentage:` | `vscode/percentage` |
|
||||
| :vscode-person: | `:vscode-person:` | `vscode/person` |
|
||||
| :vscode-person-add: | `:vscode-person-add:` | `vscode/person-add` |
|
||||
| :vscode-piano: | `:vscode-piano:` | `vscode/piano` |
|
||||
| :vscode-pie-chart: | `:vscode-pie-chart:` | `vscode/pie-chart` |
|
||||
| :vscode-pin: | `:vscode-pin:` | `vscode/pin` |
|
||||
| :vscode-pinned: | `:vscode-pinned:` | `vscode/pinned` |
|
||||
| :vscode-pinned-dirty: | `:vscode-pinned-dirty:` | `vscode/pinned-dirty` |
|
||||
| :vscode-play: | `:vscode-play:` | `vscode/play` |
|
||||
| :vscode-play-circle: | `:vscode-play-circle:` | `vscode/play-circle` |
|
||||
| :vscode-plug: | `:vscode-plug:` | `vscode/plug` |
|
||||
| :vscode-preserve-case: | `:vscode-preserve-case:` | `vscode/preserve-case` |
|
||||
| :vscode-preview: | `:vscode-preview:` | `vscode/preview` |
|
||||
| :vscode-primitive-square: | `:vscode-primitive-square:` | `vscode/primitive-square` |
|
||||
| :vscode-project: | `:vscode-project:` | `vscode/project` |
|
||||
| :vscode-pulse: | `:vscode-pulse:` | `vscode/pulse` |
|
||||
| :vscode-python: | `:vscode-python:` | `vscode/python` |
|
||||
| :vscode-question: | `:vscode-question:` | `vscode/question` |
|
||||
| :vscode-quote: | `:vscode-quote:` | `vscode/quote` |
|
||||
| :vscode-quotes: | `:vscode-quotes:` | `vscode/quotes` |
|
||||
| :vscode-radio-tower: | `:vscode-radio-tower:` | `vscode/radio-tower` |
|
||||
| :vscode-reactions: | `:vscode-reactions:` | `vscode/reactions` |
|
||||
| :vscode-record: | `:vscode-record:` | `vscode/record` |
|
||||
| :vscode-record-keys: | `:vscode-record-keys:` | `vscode/record-keys` |
|
||||
| :vscode-record-small: | `:vscode-record-small:` | `vscode/record-small` |
|
||||
| :vscode-redo: | `:vscode-redo:` | `vscode/redo` |
|
||||
| :vscode-references: | `:vscode-references:` | `vscode/references` |
|
||||
| :vscode-refresh: | `:vscode-refresh:` | `vscode/refresh` |
|
||||
| :vscode-regex: | `:vscode-regex:` | `vscode/regex` |
|
||||
| :vscode-remote: | `:vscode-remote:` | `vscode/remote` |
|
||||
| :vscode-remote-explorer: | `:vscode-remote-explorer:` | `vscode/remote-explorer` |
|
||||
| :vscode-remove: | `:vscode-remove:` | `vscode/remove` |
|
||||
| :vscode-remove-small: | `:vscode-remove-small:` | `vscode/remove-small` |
|
||||
| :vscode-rename: | `:vscode-rename:` | `vscode/rename` |
|
||||
| :vscode-replace: | `:vscode-replace:` | `vscode/replace` |
|
||||
| :vscode-replace-all: | `:vscode-replace-all:` | `vscode/replace-all` |
|
||||
| :vscode-reply: | `:vscode-reply:` | `vscode/reply` |
|
||||
| :vscode-repo: | `:vscode-repo:` | `vscode/repo` |
|
||||
| :vscode-repo-clone: | `:vscode-repo-clone:` | `vscode/repo-clone` |
|
||||
| :vscode-repo-fetch: | `:vscode-repo-fetch:` | `vscode/repo-fetch` |
|
||||
| :vscode-repo-force-push: | `:vscode-repo-force-push:` | `vscode/repo-force-push` |
|
||||
| :vscode-repo-forked: | `:vscode-repo-forked:` | `vscode/repo-forked` |
|
||||
| :vscode-repo-pinned: | `:vscode-repo-pinned:` | `vscode/repo-pinned` |
|
||||
| :vscode-repo-pull: | `:vscode-repo-pull:` | `vscode/repo-pull` |
|
||||
| :vscode-repo-push: | `:vscode-repo-push:` | `vscode/repo-push` |
|
||||
| :vscode-repo-selected: | `:vscode-repo-selected:` | `vscode/repo-selected` |
|
||||
| :vscode-report: | `:vscode-report:` | `vscode/report` |
|
||||
| :vscode-request-changes: | `:vscode-request-changes:` | `vscode/request-changes` |
|
||||
| :vscode-robot: | `:vscode-robot:` | `vscode/robot` |
|
||||
| :vscode-rocket: | `:vscode-rocket:` | `vscode/rocket` |
|
||||
| :vscode-root-folder: | `:vscode-root-folder:` | `vscode/root-folder` |
|
||||
| :vscode-root-folder-opened: | `:vscode-root-folder-opened:` | `vscode/root-folder-opened` |
|
||||
| :vscode-rss: | `:vscode-rss:` | `vscode/rss` |
|
||||
| :vscode-ruby: | `:vscode-ruby:` | `vscode/ruby` |
|
||||
| :vscode-run-above: | `:vscode-run-above:` | `vscode/run-above` |
|
||||
| :vscode-run-all: | `:vscode-run-all:` | `vscode/run-all` |
|
||||
| :vscode-run-all-coverage: | `:vscode-run-all-coverage:` | `vscode/run-all-coverage` |
|
||||
| :vscode-run-below: | `:vscode-run-below:` | `vscode/run-below` |
|
||||
| :vscode-run-coverage: | `:vscode-run-coverage:` | `vscode/run-coverage` |
|
||||
| :vscode-run-errors: | `:vscode-run-errors:` | `vscode/run-errors` |
|
||||
| :vscode-run-with-deps: | `:vscode-run-with-deps:` | `vscode/run-with-deps` |
|
||||
| :vscode-save: | `:vscode-save:` | `vscode/save` |
|
||||
| :vscode-save-all: | `:vscode-save-all:` | `vscode/save-all` |
|
||||
| :vscode-save-as: | `:vscode-save-as:` | `vscode/save-as` |
|
||||
| :vscode-screen-cut: | `:vscode-screen-cut:` | `vscode/screen-cut` |
|
||||
| :vscode-screen-full: | `:vscode-screen-full:` | `vscode/screen-full` |
|
||||
| :vscode-screen-normal: | `:vscode-screen-normal:` | `vscode/screen-normal` |
|
||||
| :vscode-search: | `:vscode-search:` | `vscode/search` |
|
||||
| :vscode-search-fuzzy: | `:vscode-search-fuzzy:` | `vscode/search-fuzzy` |
|
||||
| :vscode-search-large: | `:vscode-search-large:` | `vscode/search-large` |
|
||||
| :vscode-search-sparkle: | `:vscode-search-sparkle:` | `vscode/search-sparkle` |
|
||||
| :vscode-search-stop: | `:vscode-search-stop:` | `vscode/search-stop` |
|
||||
| :vscode-send: | `:vscode-send:` | `vscode/send` |
|
||||
| :vscode-send-to-remote-agent: | `:vscode-send-to-remote-agent:` | `vscode/send-to-remote-agent` |
|
||||
| :vscode-server: | `:vscode-server:` | `vscode/server` |
|
||||
| :vscode-server-environment: | `:vscode-server-environment:` | `vscode/server-environment` |
|
||||
| :vscode-server-process: | `:vscode-server-process:` | `vscode/server-process` |
|
||||
| :vscode-session-in-progress: | `:vscode-session-in-progress:` | `vscode/session-in-progress` |
|
||||
| :vscode-settings: | `:vscode-settings:` | `vscode/settings` |
|
||||
| :vscode-settings-gear: | `:vscode-settings-gear:` | `vscode/settings-gear` |
|
||||
| :vscode-share: | `:vscode-share:` | `vscode/share` |
|
||||
| :vscode-share-window: | `:vscode-share-window:` | `vscode/share-window` |
|
||||
| :vscode-shield: | `:vscode-shield:` | `vscode/shield` |
|
||||
| :vscode-sign-in: | `:vscode-sign-in:` | `vscode/sign-in` |
|
||||
| :vscode-sign-out: | `:vscode-sign-out:` | `vscode/sign-out` |
|
||||
| :vscode-skip: | `:vscode-skip:` | `vscode/skip` |
|
||||
| :vscode-smiley: | `:vscode-smiley:` | `vscode/smiley` |
|
||||
| :vscode-snake: | `:vscode-snake:` | `vscode/snake` |
|
||||
| :vscode-sort-precedence: | `:vscode-sort-precedence:` | `vscode/sort-precedence` |
|
||||
| :vscode-source-control: | `:vscode-source-control:` | `vscode/source-control` |
|
||||
| :vscode-sparkle: | `:vscode-sparkle:` | `vscode/sparkle` |
|
||||
| :vscode-sparkle-filled: | `:vscode-sparkle-filled:` | `vscode/sparkle-filled` |
|
||||
| :vscode-split-horizontal: | `:vscode-split-horizontal:` | `vscode/split-horizontal` |
|
||||
| :vscode-split-vertical: | `:vscode-split-vertical:` | `vscode/split-vertical` |
|
||||
| :vscode-squirrel: | `:vscode-squirrel:` | `vscode/squirrel` |
|
||||
| :vscode-star-empty: | `:vscode-star-empty:` | `vscode/star-empty` |
|
||||
| :vscode-star-full: | `:vscode-star-full:` | `vscode/star-full` |
|
||||
| :vscode-star-half: | `:vscode-star-half:` | `vscode/star-half` |
|
||||
| :vscode-stop-circle: | `:vscode-stop-circle:` | `vscode/stop-circle` |
|
||||
| :vscode-strikethrough: | `:vscode-strikethrough:` | `vscode/strikethrough` |
|
||||
| :vscode-surround-with: | `:vscode-surround-with:` | `vscode/surround-with` |
|
||||
| :vscode-symbol-array: | `:vscode-symbol-array:` | `vscode/symbol-array` |
|
||||
| :vscode-symbol-boolean: | `:vscode-symbol-boolean:` | `vscode/symbol-boolean` |
|
||||
| :vscode-symbol-class: | `:vscode-symbol-class:` | `vscode/symbol-class` |
|
||||
| :vscode-symbol-color: | `:vscode-symbol-color:` | `vscode/symbol-color` |
|
||||
| :vscode-symbol-constant: | `:vscode-symbol-constant:` | `vscode/symbol-constant` |
|
||||
| :vscode-symbol-enum: | `:vscode-symbol-enum:` | `vscode/symbol-enum` |
|
||||
| :vscode-symbol-enum-member: | `:vscode-symbol-enum-member:` | `vscode/symbol-enum-member` |
|
||||
| :vscode-symbol-event: | `:vscode-symbol-event:` | `vscode/symbol-event` |
|
||||
| :vscode-symbol-field: | `:vscode-symbol-field:` | `vscode/symbol-field` |
|
||||
| :vscode-symbol-file: | `:vscode-symbol-file:` | `vscode/symbol-file` |
|
||||
| :vscode-symbol-interface: | `:vscode-symbol-interface:` | `vscode/symbol-interface` |
|
||||
| :vscode-symbol-key: | `:vscode-symbol-key:` | `vscode/symbol-key` |
|
||||
| :vscode-symbol-keyword: | `:vscode-symbol-keyword:` | `vscode/symbol-keyword` |
|
||||
| :vscode-symbol-method: | `:vscode-symbol-method:` | `vscode/symbol-method` |
|
||||
| :vscode-symbol-method-arrow: | `:vscode-symbol-method-arrow:` | `vscode/symbol-method-arrow` |
|
||||
| :vscode-symbol-misc: | `:vscode-symbol-misc:` | `vscode/symbol-misc` |
|
||||
| :vscode-symbol-namespace: | `:vscode-symbol-namespace:` | `vscode/symbol-namespace` |
|
||||
| :vscode-symbol-numeric: | `:vscode-symbol-numeric:` | `vscode/symbol-numeric` |
|
||||
| :vscode-symbol-operator: | `:vscode-symbol-operator:` | `vscode/symbol-operator` |
|
||||
| :vscode-symbol-parameter: | `:vscode-symbol-parameter:` | `vscode/symbol-parameter` |
|
||||
| :vscode-symbol-property: | `:vscode-symbol-property:` | `vscode/symbol-property` |
|
||||
| :vscode-symbol-ruler: | `:vscode-symbol-ruler:` | `vscode/symbol-ruler` |
|
||||
| :vscode-symbol-snippet: | `:vscode-symbol-snippet:` | `vscode/symbol-snippet` |
|
||||
| :vscode-symbol-string: | `:vscode-symbol-string:` | `vscode/symbol-string` |
|
||||
| :vscode-symbol-structure: | `:vscode-symbol-structure:` | `vscode/symbol-structure` |
|
||||
| :vscode-symbol-variable: | `:vscode-symbol-variable:` | `vscode/symbol-variable` |
|
||||
| :vscode-sync: | `:vscode-sync:` | `vscode/sync` |
|
||||
| :vscode-sync-ignored: | `:vscode-sync-ignored:` | `vscode/sync-ignored` |
|
||||
| :vscode-table: | `:vscode-table:` | `vscode/table` |
|
||||
| :vscode-tag: | `:vscode-tag:` | `vscode/tag` |
|
||||
| :vscode-target: | `:vscode-target:` | `vscode/target` |
|
||||
| :vscode-tasklist: | `:vscode-tasklist:` | `vscode/tasklist` |
|
||||
| :vscode-telescope: | `:vscode-telescope:` | `vscode/telescope` |
|
||||
| :vscode-terminal: | `:vscode-terminal:` | `vscode/terminal` |
|
||||
| :vscode-terminal-bash: | `:vscode-terminal-bash:` | `vscode/terminal-bash` |
|
||||
| :vscode-terminal-cmd: | `:vscode-terminal-cmd:` | `vscode/terminal-cmd` |
|
||||
| :vscode-terminal-debian: | `:vscode-terminal-debian:` | `vscode/terminal-debian` |
|
||||
| :vscode-terminal-git-bash: | `:vscode-terminal-git-bash:` | `vscode/terminal-git-bash` |
|
||||
| :vscode-terminal-linux: | `:vscode-terminal-linux:` | `vscode/terminal-linux` |
|
||||
| :vscode-terminal-powershell: | `:vscode-terminal-powershell:` | `vscode/terminal-powershell` |
|
||||
| :vscode-terminal-secure: | `:vscode-terminal-secure:` | `vscode/terminal-secure` |
|
||||
| :vscode-terminal-tmux: | `:vscode-terminal-tmux:` | `vscode/terminal-tmux` |
|
||||
| :vscode-terminal-ubuntu: | `:vscode-terminal-ubuntu:` | `vscode/terminal-ubuntu` |
|
||||
| :vscode-text-size: | `:vscode-text-size:` | `vscode/text-size` |
|
||||
| :vscode-thinking: | `:vscode-thinking:` | `vscode/thinking` |
|
||||
| :vscode-three-bars: | `:vscode-three-bars:` | `vscode/three-bars` |
|
||||
| :vscode-thumbsdown: | `:vscode-thumbsdown:` | `vscode/thumbsdown` |
|
||||
| :vscode-thumbsdown-filled: | `:vscode-thumbsdown-filled:` | `vscode/thumbsdown-filled` |
|
||||
| :vscode-thumbsup: | `:vscode-thumbsup:` | `vscode/thumbsup` |
|
||||
| :vscode-thumbsup-filled: | `:vscode-thumbsup-filled:` | `vscode/thumbsup-filled` |
|
||||
| :vscode-tools: | `:vscode-tools:` | `vscode/tools` |
|
||||
| :vscode-trash: | `:vscode-trash:` | `vscode/trash` |
|
||||
| :vscode-triangle-down: | `:vscode-triangle-down:` | `vscode/triangle-down` |
|
||||
| :vscode-triangle-left: | `:vscode-triangle-left:` | `vscode/triangle-left` |
|
||||
| :vscode-triangle-right: | `:vscode-triangle-right:` | `vscode/triangle-right` |
|
||||
| :vscode-triangle-up: | `:vscode-triangle-up:` | `vscode/triangle-up` |
|
||||
| :vscode-twitter: | `:vscode-twitter:` | `vscode/twitter` |
|
||||
| :vscode-type-hierarchy: | `:vscode-type-hierarchy:` | `vscode/type-hierarchy` |
|
||||
| :vscode-type-hierarchy-sub: | `:vscode-type-hierarchy-sub:` | `vscode/type-hierarchy-sub` |
|
||||
| :vscode-type-hierarchy-super: | `:vscode-type-hierarchy-super:` | `vscode/type-hierarchy-super` |
|
||||
| :vscode-unarchive: | `:vscode-unarchive:` | `vscode/unarchive` |
|
||||
| :vscode-unfold: | `:vscode-unfold:` | `vscode/unfold` |
|
||||
| :vscode-ungroup-by-ref-type: | `:vscode-ungroup-by-ref-type:` | `vscode/ungroup-by-ref-type` |
|
||||
| :vscode-unlock: | `:vscode-unlock:` | `vscode/unlock` |
|
||||
| :vscode-unmute: | `:vscode-unmute:` | `vscode/unmute` |
|
||||
| :vscode-unverified: | `:vscode-unverified:` | `vscode/unverified` |
|
||||
| :vscode-variable-group: | `:vscode-variable-group:` | `vscode/variable-group` |
|
||||
| :vscode-verified: | `:vscode-verified:` | `vscode/verified` |
|
||||
| :vscode-verified-filled: | `:vscode-verified-filled:` | `vscode/verified-filled` |
|
||||
| :vscode-versions: | `:vscode-versions:` | `vscode/versions` |
|
||||
| :vscode-vm: | `:vscode-vm:` | `vscode/vm` |
|
||||
| :vscode-vm-active: | `:vscode-vm-active:` | `vscode/vm-active` |
|
||||
| :vscode-vm-connect: | `:vscode-vm-connect:` | `vscode/vm-connect` |
|
||||
| :vscode-vm-outline: | `:vscode-vm-outline:` | `vscode/vm-outline` |
|
||||
| :vscode-vm-pending: | `:vscode-vm-pending:` | `vscode/vm-pending` |
|
||||
| :vscode-vm-running: | `:vscode-vm-running:` | `vscode/vm-running` |
|
||||
| :vscode-vm-small: | `:vscode-vm-small:` | `vscode/vm-small` |
|
||||
| :vscode-vr: | `:vscode-vr:` | `vscode/vr` |
|
||||
| :vscode-vscode: | `:vscode-vscode:` | `vscode/vscode` |
|
||||
| :vscode-vscode-insiders: | `:vscode-vscode-insiders:` | `vscode/vscode-insiders` |
|
||||
| :vscode-wand: | `:vscode-wand:` | `vscode/wand` |
|
||||
| :vscode-warning: | `:vscode-warning:` | `vscode/warning` |
|
||||
| :vscode-watch: | `:vscode-watch:` | `vscode/watch` |
|
||||
| :vscode-whitespace: | `:vscode-whitespace:` | `vscode/whitespace` |
|
||||
| :vscode-whole-word: | `:vscode-whole-word:` | `vscode/whole-word` |
|
||||
| :vscode-window: | `:vscode-window:` | `vscode/window` |
|
||||
| :vscode-window-active: | `:vscode-window-active:` | `vscode/window-active` |
|
||||
| :vscode-word-wrap: | `:vscode-word-wrap:` | `vscode/word-wrap` |
|
||||
| :vscode-workspace-trusted: | `:vscode-workspace-trusted:` | `vscode/workspace-trusted` |
|
||||
| :vscode-workspace-unknown: | `:vscode-workspace-unknown:` | `vscode/workspace-unknown` |
|
||||
| :vscode-workspace-untrusted: | `:vscode-workspace-untrusted:` | `vscode/workspace-untrusted` |
|
||||
| :vscode-worktree: | `:vscode-worktree:` | `vscode/worktree` |
|
||||
| :vscode-worktree-small: | `:vscode-worktree-small:` | `vscode/worktree-small` |
|
||||
| :vscode-zoom-in: | `:vscode-zoom-in:` | `vscode/zoom-in` |
|
||||
| :vscode-zoom-out: | `:vscode-zoom-out:` | `vscode/zoom-out` |
|
||||
@@ -0,0 +1,306 @@
|
||||
# Компоненты
|
||||
|
||||
Здесь показаны примеры компонентов, которые можно внедрять в документацию.
|
||||
|
||||
Для синтаксиса обращайся в [документацию Zensical][1] и репозиторий [этой документации][2].
|
||||
|
||||
[1]: https://zensical.org/docs
|
||||
[2]: https://git.axenov.dev/IPTV/docs
|
||||
|
||||
## Мелочёвка
|
||||
|
||||
=== "Бейджи"
|
||||
|
||||
Это кастомный функционал, в основе которого лежит `inline_badges.py` в корне репозитория.
|
||||
|
||||
<!-- md:env SOME_VAR -->
|
||||
<!-- md:arg --arg -->
|
||||
<!-- md:config server.host -->
|
||||
<!-- md:version 1.2.3 -->
|
||||
<!-- md:default default_value -->
|
||||
<!-- md:beta -->
|
||||
|
||||
=== "Frontmatter"
|
||||
|
||||
```yaml
|
||||
---
|
||||
title: My Page
|
||||
description: Some page description
|
||||
icon: material/star
|
||||
tags: [tag1, tag2]
|
||||
hide: [navigation, toc, path]
|
||||
status: new
|
||||
#status: deprecated
|
||||
#status: beta
|
||||
---
|
||||
|
||||
# My Super-Duper Page
|
||||
|
||||
# Markdown content goes here
|
||||
```
|
||||
|
||||
=== "Тултипы"
|
||||
|
||||
:material-information-outline:{ title="текст подсказки" }
|
||||
|
||||
[Hover me 1](https://example.com "I'm first tooltip!")
|
||||
|
||||
[Hover me 2][example]
|
||||
|
||||
[example]: https://example.com "I'm second tooltip!"
|
||||
|
||||
=== "Кнопки"
|
||||
|
||||
[Серая кнопка](https://example.com/){ .md-button }
|
||||
|
||||
[Синяя кнопка](https://example.com/){ .md-button .md-button--primary }
|
||||
|
||||
[:fontawesome-solid-paper-plane: Кнопка серая с иконкой и подсказкой](https://example.com/){ .md-button title="текст подсказки 2" }
|
||||
|
||||
[:fontawesome-solid-paper-plane: Кнопка синяя с иконкой](https://example.com/){ .md-button .md-button--primary }
|
||||
|
||||
---
|
||||
|
||||
=== "Простой блок"
|
||||
|
||||
```python
|
||||
def _render_icon(shortcode: str, md) -> str:
|
||||
emoji_pattern = md.inlinePatterns.get("emoji")
|
||||
if emoji_pattern is None:
|
||||
return escape(shortcode)
|
||||
```
|
||||
|
||||
=== "С аннотациями"
|
||||
|
||||
```python
|
||||
def _render_icon(shortcode: str, md) -> str: #(1)!
|
||||
emoji_pattern = md.inlinePatterns.get("emoji") #(2)!
|
||||
if emoji_pattern is None:
|
||||
return escape(shortcode) #(3)!
|
||||
```
|
||||
|
||||
1. сигнатура функции
|
||||
2. инициализация переменной
|
||||
3. возврат результата
|
||||
|
||||
=== "С заголовком"
|
||||
|
||||
```python title="example.py"
|
||||
def _render_icon(shortcode: str, md) -> str:
|
||||
emoji_pattern = md.inlinePatterns.get("emoji")
|
||||
if emoji_pattern is None:
|
||||
return escape(shortcode)
|
||||
```
|
||||
|
||||
=== "Нумерация с 5"
|
||||
|
||||
```python linenums="5"
|
||||
def _render_icon(shortcode: str, md) -> str:
|
||||
emoji_pattern = md.inlinePatterns.get("emoji")
|
||||
if emoji_pattern is None:
|
||||
return escape(shortcode)
|
||||
```
|
||||
|
||||
=== "Выделение"
|
||||
|
||||
```python linenums="1" hl_lines="2-5 8 9 22"
|
||||
def _render_icon(shortcode: str, md) -> str:
|
||||
try:
|
||||
emoji_pattern = md.inlinePatterns["emoji"]
|
||||
except KeyError:
|
||||
return escape(shortcode)
|
||||
|
||||
icon = emoji_pattern.emoji_index["emoji"].get(shortcode)
|
||||
if icon is None:
|
||||
return escape(shortcode)
|
||||
|
||||
element = emoji_pattern.generator(
|
||||
emoji_pattern.emoji_index["name"],
|
||||
shortcode,
|
||||
None,
|
||||
None,
|
||||
shortcode,
|
||||
"",
|
||||
icon.get("category", ""),
|
||||
emoji_pattern.options,
|
||||
md,
|
||||
)
|
||||
return tostring(element, encoding="unicode", method="html")
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Врезки
|
||||
|
||||
=== "Полные"
|
||||
|
||||
!!! note "Заголовок статичной врезки"
|
||||
Содержимое, которое может
|
||||
быть многострочным
|
||||
|
||||
!!! abstract "Заголовок статичной врезки"
|
||||
Содержимое, которое может
|
||||
быть многострочным
|
||||
|
||||
!!! info "Заголовок статичной врезки"
|
||||
Содержимое, которое может
|
||||
быть многострочным
|
||||
|
||||
!!! tip "Заголовок статичной врезки"
|
||||
Содержимое, которое может
|
||||
быть многострочным
|
||||
|
||||
!!! success "Заголовок статичной врезки"
|
||||
Содержимое, которое может
|
||||
быть многострочным
|
||||
|
||||
!!! question "Заголовок статичной врезки"
|
||||
Содержимое, которое может
|
||||
быть многострочным
|
||||
|
||||
!!! warning "Заголовок статичной врезки"
|
||||
Содержимое, которое может
|
||||
быть многострочным
|
||||
|
||||
!!! failure "Заголовок статичной врезки"
|
||||
Содержимое, которое может
|
||||
быть многострочным
|
||||
|
||||
!!! danger "Заголовок статичной врезки"
|
||||
Содержимое, которое может
|
||||
быть многострочным
|
||||
|
||||
!!! bug "Заголовок статичной врезки"
|
||||
Содержимое, которое может
|
||||
быть многострочным
|
||||
|
||||
!!! example "Заголовок статичной врезки"
|
||||
Содержимое, которое может
|
||||
быть многострочным
|
||||
|
||||
!!! quote "Заголовок статичной врезки"
|
||||
Содержимое, которое может
|
||||
быть многострочным
|
||||
|
||||
=== "Свёрнутые"
|
||||
|
||||
??? note "Заголовок свёрнутой врезки"
|
||||
Содержимое, которое может
|
||||
быть многострочным
|
||||
|
||||
??? abstract "Заголовок свёрнутой врезки"
|
||||
Содержимое, которое может
|
||||
быть многострочным
|
||||
|
||||
??? info "Заголовок свёрнутой врезки"
|
||||
Содержимое, которое может
|
||||
быть многострочным
|
||||
|
||||
??? tip "Заголовок свёрнутой врезки"
|
||||
Содержимое, которое может
|
||||
быть многострочным
|
||||
|
||||
??? success "Заголовок свёрнутой врезки"
|
||||
Содержимое, которое может
|
||||
быть многострочным
|
||||
|
||||
??? question "Заголовок свёрнутой врезки"
|
||||
Содержимое, которое может
|
||||
быть многострочным
|
||||
|
||||
??? warning "Заголовок свёрнутой врезки"
|
||||
Содержимое, которое может
|
||||
быть многострочным
|
||||
|
||||
??? failure "Заголовок свёрнутой врезки"
|
||||
Содержимое, которое может
|
||||
быть многострочным
|
||||
|
||||
??? danger "Заголовок свёрнутой врезки"
|
||||
Содержимое, которое может
|
||||
быть многострочным
|
||||
|
||||
??? bug "Заголовок свёрнутой врезки"
|
||||
Содержимое, которое может
|
||||
быть многострочным
|
||||
|
||||
??? example "Заголовок свёрнутой врезки"
|
||||
Содержимое, которое может
|
||||
быть многострочным
|
||||
|
||||
??? quote "Заголовок свёрнутой врезки"
|
||||
Содержимое, которое может
|
||||
быть многострочным
|
||||
|
||||
=== "Сворачиваемые"
|
||||
|
||||
???+ note "Заголовок развёрнутой врезки"
|
||||
Содержимое, которое может
|
||||
быть многострочным
|
||||
|
||||
???+ abstract "Заголовок развёрнутой врезки"
|
||||
Содержимое, которое может
|
||||
быть многострочным
|
||||
|
||||
???+ info "Заголовок развёрнутой врезки"
|
||||
Содержимое, которое может
|
||||
быть многострочным
|
||||
|
||||
???+ tip "Заголовок развёрнутой врезки"
|
||||
Содержимое, которое может
|
||||
быть многострочным
|
||||
|
||||
???+ success "Заголовок развёрнутой врезки"
|
||||
Содержимое, которое может
|
||||
быть многострочным
|
||||
|
||||
???+ question "Заголовок развёрнутой врезки"
|
||||
Содержимое, которое может
|
||||
быть многострочным
|
||||
|
||||
???+ warning "Заголовок развёрнутой врезки"
|
||||
Содержимое, которое может
|
||||
быть многострочным
|
||||
|
||||
???+ failure "Заголовок развёрнутой врезки"
|
||||
Содержимое, которое может
|
||||
быть многострочным
|
||||
|
||||
???+ danger "Заголовок развёрнутой врезки"
|
||||
Содержимое, которое может
|
||||
быть многострочным
|
||||
|
||||
???+ bug "Заголовок развёрнутой врезки"
|
||||
Содержимое, которое может
|
||||
быть многострочным
|
||||
|
||||
???+ example "Заголовок развёрнутой врезки"
|
||||
Содержимое, которое может
|
||||
быть многострочным
|
||||
|
||||
???+ quote "Заголовок развёрнутой врезки"
|
||||
Содержимое, которое может
|
||||
быть многострочным
|
||||
|
||||
=== "Короткие"
|
||||
|
||||
!!! note
|
||||
Дефолтный заголовок
|
||||
|
||||
!!! abstract ""
|
||||
Пустой заголовок
|
||||
|
||||
!!! info "Пустое содержимое"
|
||||
|
||||
=== "Кастомные"
|
||||
|
||||
??? image "Врезка для скриншота"
|
||||
Тут должна быть картинка
|
||||
|
||||
!!! boosty "Врезка Boosty"
|
||||
Тут должна быть релевантная информация
|
||||
|
||||
!!! yoomoney "Врезка Yoomoney"
|
||||
Тут должна быть релевантная информация
|
||||
|
||||
---
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,71 @@
|
||||
---
|
||||
icon: material/application-brackets-outline
|
||||
tags: ["iptvc", "разработка"]
|
||||
---
|
||||
|
||||
# :material-application-brackets-outline: Среда разработки
|
||||
|
||||
## Быстрый старт
|
||||
|
||||
Для локальной разработки `iptvc` достаточно установить [Go 1.23.6+][1] и клонировать репозиторий:
|
||||
|
||||
```bash
|
||||
git clone https://git.axenov.dev/IPTV/iptvc.git
|
||||
cd iptvc
|
||||
go run . serve -i playlists.ini -p 8080 --check
|
||||
```
|
||||
|
||||
Веб-интерфейс будет доступен по адресу <http://localhost:8080>.
|
||||
|
||||
## Требования
|
||||
|
||||
| ПО | Версия | Назначение |
|
||||
| ----------- | --------------------- | ------------------------------------- |
|
||||
| [Go][1] | 1.23.6+ | Компиляция и запуск |
|
||||
| [Make][2] | любая | Сборка через `Makefile` (опционально) |
|
||||
| [Docker][3] | с `docker compose` v2 | Полное окружение (опционально) |
|
||||
|
||||
[1]: https://go.dev/dl/
|
||||
[2]: https://www.gnu.org/software/make
|
||||
[3]: https://docs.docker.com/engine/install
|
||||
|
||||
|
||||
## Команды для разработки
|
||||
|
||||
```bash
|
||||
# Запуск веб-сервера с фоновой проверкой
|
||||
go run . serve -i playlists.ini -p 8080 --check
|
||||
|
||||
# Запуск проверки без веб-сервера
|
||||
go run . check -i playlists.ini --repeat 1
|
||||
|
||||
# Сборка бинарника
|
||||
go build -o iptvc .
|
||||
|
||||
# Проверка кода
|
||||
go vet ./...
|
||||
|
||||
# Сборка под все платформы
|
||||
make release
|
||||
```
|
||||
|
||||
## Файлы конфигурации
|
||||
|
||||
Для работы `iptvc` нужны два файла рядом с бинарником:
|
||||
|
||||
- `playlists.ini` — список плейлистов. Формат описан в [справочнике форматов](../../common/formats/playlists.md).
|
||||
- `channels.json` — правила тегов каналов. Формат описан в [справочнике форматов](../../common/formats/channels.md).
|
||||
- `config.yml` — конфигурация программы. Описание — в [разделе config.yml](../../common/config/config.md).
|
||||
|
||||
## Полное Docker-окружение
|
||||
|
||||
Полная инфраструктура проекта (nginx, KeyDB, checker, docs) развёртывается через Docker.
|
||||
|
||||
Подробнее — в разделе [Развёртывание](../site/deploy.md).
|
||||
|
||||
## Дополнительные материалы
|
||||
|
||||
- [Компиляция из исходного кода](compile.md)
|
||||
- [Построение Docker-образа](docker.md)
|
||||
- [Архитектура iptvc](arch.md)
|
||||
- [Развёртывание и доставка обновлений](../site/deploy.md)
|
||||
@@ -0,0 +1,80 @@
|
||||
---
|
||||
icon: material/robot-outline
|
||||
---
|
||||
|
||||
# :material-robot-outline: Telegram-бот
|
||||
|
||||
!!! info "Обрати внимание"
|
||||
Локальная среда разработки должна быть [настроена и запущена](local-dev.md).
|
||||
|
||||
## Подготовка бота на стороне Telegram
|
||||
|
||||
1. Написать [@botfather](https://t.me/botfather), создать бота
|
||||
2. Полученный токен установить значением переменной `TG_BOT_TOKEN` в файле `.env` репозитория `web`
|
||||
3. Командой `/mybots` в [@botfather](https://t.me/botfather) выбрать свежесозданного бота, далее `Edit Bot` > `Edit Commands` и отправить текст:
|
||||
```
|
||||
list - Список плейлистов
|
||||
info - Подробности о плейлисте по его коду
|
||||
help - Помощь по командам бота
|
||||
links - Ссылки на все страницы проекта
|
||||
stats - Статистика по плейлистам и каналам
|
||||
```
|
||||
|
||||
## Проброс внешних запросов на локальную машину
|
||||
|
||||
1. Установить [telebit](https://telebit.cloud) и пройти примитивную регистрацию.
|
||||
В результате будет выдан уникальный адрес в формате `https://foo-bar-99.telebit.io`.
|
||||
На email, указанный при регистрации, будет оформлен бесплатный SSL-серификат Let's Encrypt для этого домена.
|
||||
Если адрес не используется месяц+, то сертификат протухнет, но он автоматически восстановится, если адрес начнёт использоваться вновь.
|
||||
|
||||
2. В терминале выполнить:
|
||||
```
|
||||
telebit http 8080
|
||||
```
|
||||
где `8080` — порт локальной машины, на который проброшен порт 80 из контейнера `iptv-nginx`.
|
||||
Для выключения выполнить:
|
||||
```
|
||||
telebit http
|
||||
```
|
||||
|
||||
3. Проверить работу адреса, перейдя по нему браузером.
|
||||
Должен открыться твой локальный проект.
|
||||
|
||||
4. Полученный адрес установить значением переменной `APP_URL` в файле `.env` репозитория `web`
|
||||
|
||||
5. Установить веб-хук, отправив запрос браузером или любым HTTP-клиентом на адрес:
|
||||
```
|
||||
https://api.telegram.org/bot$BOT_TOKEN/setWebhook?url=$TELEBIT_URL/bot/webhook&secret_token=$SECRET_TOKEN
|
||||
```
|
||||
где:
|
||||
* `$BOT_TOKEN` - авторизационный токен, который @botfather выдал твоему боту;
|
||||
* `$TELEBIT_URL` - адрес, который telebit выдал тебе;
|
||||
* `$SECRET_TOKEN` - секретный токен, опционален, см. ниже.
|
||||
|
||||
6. Проверить веб-хук, отправив запрос браузером или любым HTTP-клиентом на адрес:
|
||||
```
|
||||
https://api.telegram.org/bot$BOT_TOKEN/getWebhookInfo
|
||||
```
|
||||
где:
|
||||
* `$BOT_TOKEN` - авторизационный токен, который @botfather выдал твоему боту.
|
||||
|
||||
7. После разработки нужно установить "боевой" адрес веб-хука аналогично п4.
|
||||
|
||||
## Что за секретный токен?
|
||||
|
||||
Telegram авторизует твоего бота по токену, который выдал ему сам.
|
||||
|
||||
Ты тоже можешь (не) авторизовать Telegram по токену, который ты выдашь ему.
|
||||
|
||||
Для этого нужно в значением переменной `TG_BOT_SECRET` в файле `.env` репозитория `web` установить любую строку.
|
||||
Если ты это сделаешь, тогда ту же строку ты должен передать в параметре `secret_token` метода `setWebhook`.
|
||||
|
||||
В этом случае, все HTTP-запросы, которые приходят от Telegram, будут содержать заголовок `X-Telegram-Bot-Api-Secret-Token` со этой строкой в качестве значения.
|
||||
Эта строка сверяется с той, что указана в `.env` проекта.
|
||||
Если такого заголовка нет или его значение некорректно, входящий запрос отклоняется.
|
||||
|
||||
Если переменная `TG_BOT_SECRET` не задана, то заголовок проверяться не будет.
|
||||
|
||||
См. подробности в документации: [setWebhook](https://core.telegram.org/bots/api#setwebhook)
|
||||
|
||||
|
||||
Reference in New Issue
Block a user