thindf - novo formato de dados de texto (alternativo ao JSON)

Arquivo AppData \ Local \ Dropbox \ info.json:
{ "personal": { "host": 5060852864, "is_team": false, "subscription_type": "Basic", "path": "C:\\Users\\DNS\\Dropbox" } } 
No novo formato, fica assim:
 personal host = 5060852864 is_team = 0B subscription_type = Basic path = C:\Users\DNS\Dropbox 
Arquivo de configuração do Sublime Text Editor:
 { "added_words": [ "plugin", "habrahabr", "" ], "default_line_ending": "unix", //"font_face": "Fira Code", "font_size": 11, "ignored_packages": [ "Sublimerge Pro", "Vintage" ], "ignored_words": [ "utf" ], "line_numbers": false, "show_encoding": true, "show_line_endings": true, "tab_size": 4, "theme": "Default.sublime-theme" } 
No novo formato, fica assim:
 added_words = [ plugin habrahabr  ] default_line_ending = unix //font_face = Fira Code font_size = 11 ignored_packages = [ Sublimerge Pro Vintage ] ignored_words = [ utf ] line_numbers = 0B show_encoding = 1B show_line_endings = 1B tab_size = 4 theme = Default.sublime-theme 

Um pouco de história


Esse formato deve sua aparência a outro formato com o nome estranho blockpar.
Blockpar foi desenvolvido por Alexey Dubovoi (um dos fundadores da Elemental Games) no processo de trabalhar no jogo Space Rangers. Posteriormente, Alexander Zeberg (ex-programador principal da Katauri Interactive [ depois de deixar a empresa para a Katauri Interactive e Elemental Games, ele partiu para a Katauri ] ) decidiu usar esse formato para o jogo King's Bounty: Legend of the Knight.

A definição de cada objeto do jogo foi armazenada no formato blockpar em um arquivo separado com a extensão .atom, por exemplo, aqui está um recorte do arquivo data / data.kfs / spider.atom :
 main { class=chesspiece model=spider.bma cullcat=0 } arena_params { race=neutral cost=24 level=1 leadership=14 attack=4 defense=4 ... resistances { physical=20 poison=0 magic=0 fire=-10 } ... } ... 

Posteriormente [ enquanto trabalhava no projeto Royal Quest ] , expandi esse formato um pouco para que, em vez de:
 button { name=close pos=400,600 size=200,40 image=button_close.png anchors=0,0,100,0 } 
escreva assim:
 button=close,400,600,200,40 { image=button_close.png anchors=0,0,100,0 } 

Também adicionei suporte para valores de cadeia de linhas múltiplas através do apóstrofo posterior (backtick - `):
 button=... { onmouseover=` ... ` } 
Por que recusei `cordas entre apóstrofos reversos`
No valor do parâmetro, é permitido colar diretamente o código do script e nos comentários no código eu uso apóstrofos inversos no mesmo significado que eles são usados ​​no Markdown e na marcação pc . Por exemplo:
 if len(indentation_levels) and indentation_levels[-1][0] == -1: #    `{`    ,       `}` 

E, finalmente, como resultado do meu conhecimento do Python, a idéia de rejeitar colchetes me cativou tanto que eu decidi que o formato blockpar poderia ser mais simplificado [ abandonando os colchetes necessários ] .

Também influenciado por:
  • O formato de armazenamento de texto na Yet Another Serialization Library usado pelo cliente Royal Quest.
  • O formato do arquivo de configuração nginx (no entanto, rejeitei a ideia de abandonar o delimitador (símbolo = ou : entre o nome do parâmetro e seu valor ( por que )).
  • YAML (ou seja, a ideia a ser usada . Antes do nome do elemento da matriz [ no YAML usa - ] ).

Por que 0V e 1V?
  • Frequentemente, true / false é usado com yes / no (YES / NO é usado no Objective-C) , liga / desliga ou ativa / desativa (por exemplo: você pode ativar as terminações da linha de exibição; ativar / desativar o log; é um dígito? Sim ), e na álgebra booleana, 0 e 1 são usados; portanto, o uso das palavras-chave true e false na maioria dos casos é bastante discutível.
  • Não gosto de true / false na versão russa do formato, e 0B e 1B (aqui B é a letra maiúscula russa c) podem ser associados a 0Off e 1On. [ Peço que você não levante a questão da adequação da versão russa. ]
  • 0B e 1B são usados ​​na linguagem de programação 11l pelos motivos indicados na documentação .

Seqüências de caracteres entre aspas simples


Outro [ além de 0B e 1B ] elemento controverso / incomum desse formato é o uso de aspas duplas '' para strings brutas [ sem seqüências de escape \ seqüências de escape ] .
Mas minha escolha se justifica pelo fato de o Consórcio Unicode aprovar este ano como o código para a abertura de aspas duplas .

Como digitar essas citações no teclado - veja aqui .

Se houver aspas não emparelhadas na linha, será necessário executar o "balanceamento de linha" da mesma maneira que na marcação do PC para inserir o código HTML.
Por exemplo, há uma linha don't .
Como ele contém uma cotação de fechamento desequilibrada, adicione uma cotação de abertura de equilíbrio no início da linha: ' don't .
Colocamos a string balanceada entre aspas duplas: ' 'don't ' .
Agora, você precisa mostrar de alguma forma ao analisador que a cotação adicionada à esquerda não deve ser incluída na sequência, pois é necessária apenas para restaurar o equilíbrio . Para fazer isso, use o símbolo do apóstrofo datilografado ', que deve ser colocado uma peça para cada aspas de equilíbrio [ assim, um apóstrofe datilografado “come” um par de aspas ) ; nesse caso, ele deve ser colocado no início da linha: '''don't' .
Você pode inserir uma linha balanceada como em outras linhas entre aspas duplas:
'text = '''don't'' .

Use


No momento, há uma implementação em Python e JavaScript (você pode tentar converter JSON para um novo formato diretamente no navegador na página da web do projeto ).

Para Python - instale como de costume:
 pip install thindf 

Para JavaScript:
 npm install thindf node const thindf = require('thindf'); 

E use:
  • thindf.to_thindf(object, indent = 4) para obter uma string no formato thindf correspondente ao objeto passado (análogo de json.dumps e JSON.stringify ).
  • thindf.parse(str) para obter um objeto de uma sequência no formato thindf (análogo ao json.loads e JSON.parse ).

Concluindo, darei mais alguns exemplos:
Algumas linhas do meu mapa de teclas padrão (Windows) .sublime :
 [ { "keys": ["f4"], "command": "f4" }, { "keys": ["shift+f4"], "command": "f4", "args": {"shift_key_pressed": true} }, { "keys": ["alt+shift+`"], "command": "insert", "args": {"characters": "`"} }, // ( { "keys": [":", ")"], "command": "insert_snippet", "args": {"contents": ":)(:"} }, { "keys": ["alt+9"], "context": [{"key": "selector", "operator": "equal", "operand": "text.pq"}], "command": "insert_pq" }, // ' (for balance) { "keys": ["alt+0"], "context": [{"key": "selector", "operator": "equal", "operand": "text.pq"}], "command": "insert", "args": {"characters": "'"} }, ] 
Usando o novo formato, eu escreveria o seguinte:
 f4 = on_f4() shift+f4 = on_f4(shift_key_pressed' 1B) alt+shift+` = insert(characters' '`') // ( :,) = insert_snippet(contents' ':)(:') alt+9 = if selector == 'text.pq' {insert_pq()} else 0B // ' (for balance) alt+0 = if selector == 'text.pq' {insert(characters' "'")} else 0B 

Uma parte do arquivo d.json [ do repositório do gerenciador de plugins do Sublime Text ] :
 { "schema_version": "3.0.0", "packages": [ { "name": "Django Lookup Snippets", "details": "https://github.com/icycandle/sublime-django-lookup", "releases": [ { "sublime_text": "*", "tags": true } ] }, { "name": "Django Manage Commands", "details": "https://github.com/vladimirnani/DjangoCommands", "labels": ["Django", "python", "web", "management"], "releases": [ { "sublime_text": "<3000", "tags": "st2-" }, { "sublime_text": ">=3000", "tags": "st3-" } ] } ] } 
No novo formato, fica assim:
 schema_version = '3.0.0' packages = [ . name = Django Lookup Snippets details = https://github.com/icycandle/sublime-django-lookup releases = [ . sublime_text = * tags = 1B ] . name = Django Manage Commands details = https://github.com/vladimirnani/DjangoCommands labels = [ Django python web management ] releases = [ . sublime_text = <3000 tags = st2- . sublime_text = >=3000 tags = st3- ] ] 

Alguns casos de canto:
 { "a": "'...'", "b": "string which ends with a space ", "cd": "\n", "e ": "3", "dirs": [ ["Doc,Scans", ".t'xt"] ], "node": null, "n" : "N", "files": [], "f": "[]", "ff": [ [] ], "products": {} } 
 a = ''...'' b = 'string which ends with a space ' cd = "\n" 'e ' = '3' dirs = [ ['Doc,Scans', '''.t'xt'] ] node = N n = 'N' files = [] f = '[]' ff = [ [] ] products = {} 

Source: https://habr.com/ru/post/pt419361/


All Articles