9 pontos por GN⁺ 3 일 전 | 1 comentários | Compartilhar no WhatsApp
  • Ao portar de volta o framework clássico de UI em texto para uso em Linux e Windows, ele oferece uma base comum de desenvolvimento com UTF-8 e até cores estendidas
  • Mantém ao máximo a compatibilidade em nível de código-fonte com apps Turbo Vision existentes e, ao mesmo tempo, continua usando uma API baseada em char, absorvendo dentro da biblioteca as diferenças entre terminais de cada plataforma
  • Integra entrada e exibição Unicode em todo o framework, permitindo lidar em conjunto com caracteres de largura dupla, caracteres combinantes, atalhos multibyte e edição e renderização baseadas em UTF-8
  • Traz widgets básicos como janelas sobrepostas, menus, caixas de diálogo, campos de entrada e barras de rolagem, além de suportar comportamentos modernos como loop de eventos, temporizadores, área de transferência, roda do mouse, redimensionamento e edição de arquivos grandes
  • Vai além da antiga API centrada em 16 cores ao reunir cores de 24 bits, paleta xterm-256, área de transferência do sistema e suporte a vários ambientes de console, servindo como ponte entre código TUI legado e terminais modernos

Natureza do projeto e direção principal

  • Um port moderno do Turbo Vision 2.0 que permite reutilizar o framework clássico de UI em texto em Linux e Windows, incorporando também UTF-8 e cores estendidas
  • No início, o foco foi adicionar suporte a Linux, manter o comportamento existente em DOS/Windows e preservar a compatibilidade em nível de código-fonte com apps antigos do Turbo Vision
    • Para essa compatibilidade, algumas funções da RTL do Borland C++ também foram implementadas diretamente
  • Entre julho e agosto de 2020, foi integrado suporte completo a Unicode à estrutura existente e, nesse processo, o editor de texto Turbo também foi criado
  • Envolve e abstrai as diferenças de recursos e o tratamento direto de I/O de terminal para que os aplicativos não precisem contornar essas questões por conta própria, deixando as diferenças entre plataformas a cargo da biblioteca
  • O foco é permitir escrever UIs em texto com o mesmo código em Linux e Windows, mantendo uma API baseada em char em vez de wchar_t ou TCHAR

Por que isso é útil

  • Fornece várias classes de widgets, permitindo usar de imediato janelas sobrepostas redimensionáveis, menus suspensos, caixas de diálogo, botões, barras de rolagem, campos de entrada, caixas de seleção e botões de opção
  • Mesmo ao criar widgets próprios, reduz a necessidade de reescrever tratamentos comuns como despacho de eventos ou exibição de caracteres Unicode de largura total
  • Busca produzir o mesmo resultado tanto quanto possível em cada ambiente
    • Mesmo quando cores de fundo brilhantes no console do Linux dependem do atributo blink, a biblioteca lida com isso por você
  • Aproveita o suporte a UTF-8 do setlocale na RTL da Microsoft para que, no Windows, código como std::ifstream f("コンピュータ.txt"); funcione como esperado
    • No Windows, a RTL converte imediatamente o nome do arquivo para a codificação do sistema

Projeto Unicode e processamento de texto

  • Adota UTF-8 como codificação padrão para entrada e exibição
    • É compatível com o tipo de dado char * já existente e com a mesma codificação usada no I/O do terminal, reduzindo conversões desnecessárias
    • Também está alinhado com o UTF-8 Everywhere Manifesto
  • Ao compilar com Borland C++, Unicode não é suportado, mas as extensões da API foram projetadas para permitir escrever código independente de codificação
  • Em KeyDownEvent, além de charScan.charCode, foram adicionados text[4] e textLength, que entregam diretamente a sequência de bytes UTF-8 da entrada
    • Em charScan.charCode, por compatibilidade retroativa, continua entrando o caractere com base em CP437
    • Recomenda-se usar getText() para obter uma string view
  • Os exemplos de entrada mostram exatamente como Unicode e código legado funcionam juntos
    • Ao inserir ñ, o resultado é charCode=164 ('ñ'), text={'\xC3','\xB1'}, textLength=2
    • Ao inserir , como não existe em CP437, o resultado é keyCode=0x0, charCode=0, text={'\xE2','\x82','\xAC'}, textLength=3
    • Ao inserir um atalho, textLength=0 fica vazio
  • TScreenCell pode armazenar code points UTF-8 e atributos estendidos como negrito, sublinhado e itálico
    • Caracteres de controle ASCII são tratados como caracteres de página de código
    • UTF-8 válido é exibido como está, e UTF-8 inválido é tratado como caractere de página de código
    • É possível misturar ASCII estendido e UTF-8, o que ajuda na compatibilidade retroativa, mas também pode gerar resultados inesperados
  • Caracteres de largura dupla e caracteres combinantes também recebem tratamento específico
    • Caracteres combinantes são sobrepostos ao caractere anterior
    • ZERO WIDTH JOINER U+200D é sempre omitido
    • Se o terminal respeitar a largura de caractere segundo wcwidth, quase não há artefatos visuais perceptíveis
    • Há um exemplo em Wide character display

API Unicode e suporte a views padrão

  • API de desenho com reconhecimento de Unicode

    • TDrawBuffer::moveChar, putChar tratam char c como caractere de code page
    • moveStr, moveCStr recebem TStringView e tratam strings segundo as regras de Unicode
      • maxStrWidth usa como base o número de colunas, não o de bytes
      • strIndent também usa como base o número de colunas, não o de bytes, então pode ser usado para rolagem horizontal
      • O valor de retorno é a largura de exibição do texto copiado
    • moveBuf foi mantida por ser a função que tratava strings não terminadas em null antes da introdução de TStringView
    • cstrlen(TStringView s) retorna o comprimento de exibição excluindo ~, e strwidth(TStringView s) retorna o comprimento de exibição incluindo ~
  • Simplificação de draw() e redução de bugs

    • O TFileViewer::draw() original copiava substrings para um buffer temporário antes de chamar moveStr, mas essa abordagem trazia risco de buffer overrun e problemas nos limites de caracteres multibyte
    • Depois da correção, isso passou a ser feito em uma única linha, b.moveStr(0, p, c, size.x, delta.x);, eliminando a cópia intermediária
      • delta.x pode ser aplicado diretamente com base em colunas
      • Como no máximo size.x colunas são copiadas, diminui a necessidade de calcular manualmente o número de bytes e as condições de contorno
  • Views padrão com suporte à exibição Unicode

  • Views que também processam entrada Unicode

    • TInputLine, cb489d42, TEditor e os atalhos de TMenuView também processam entrada de usuário em Unicode
    • Instâncias de TEditor ficam em modo UTF-8 por padrão, e é possível alternar para o modo single-byte com Ctrl+P
    • Essa alternância não muda o conteúdo do documento, apenas a forma de exibição e a codificação de entrada
    • Teclas de atalho destacadas de TStatusLine, TButton e afins não são suportadas
  • Strings multilíngues em menu e barra de status

    • Strings como ~Ñ~ello, 階~毎~料入報最..., 五劫~の~擦り切れ, העברית ~א~ינטרנט, ~Alt-Ç~ Exit podem ser usadas diretamente em menus e na barra de status
    • A tela resultante pode ser vista em Unicode Hello

Modelo de funcionamento por plataforma

  • Unix

    • Usa suporte a terminal baseado em Ncurses
    • Suporta codificação de mouse X10 e SGR, modifyOtherKeys do xterm, fixterms de Paul Evans, o keyboard protocol do Kitty, o win32-input-mode do WSL Conpty, far2l, modificadores TIOCLINUX do console Linux e o mouse GPM
    • Possui um manipulador de sinais personalizado para restaurar o estado do terminal antes que o programa termine de forma anormal
    • Se stderr for um tty, a saída é armazenada em buffer e exibida ao encerrar ou suspender para evitar corrupção da tela
      • Como há limite de tamanho do buffer, gravações em stderr podem falhar quando ele encher
      • Para preservar tudo, recomenda-se redirecionar com 2>
    • Lê as variáveis de ambiente TERM, COLORTERM, ESCDELAY e TVISION_USE_STDIO
      • Se COLORTERM=truecolor ou 24bit, assume cores de 24 bits
      • O valor padrão de ESCDELAY é 10 ms
      • Se TVISION_USE_STDIO não estiver vazia, faz I/O por stdin e stdout em vez de /dev/tty
  • Windows

    • Compatível apenas com a Win32 Console API
    • Em emuladores de terminal que não a suportam, abre automaticamente uma janela de console separada
    • O layout da aplicação se baseia no tamanho da janela do console, não no buffer do console, e restaura o buffer ao encerrar ou suspender
    • Quando não é Borland C++, muda a code page do console para UTF-8 na inicialização e a restaura ao sair
    • Também muda o runtime Microsoft C para o modo UTF-8, reduzindo a necessidade de o desenvolvedor usar diretamente variantes wchar_t
    • Na combinação de modo legado com fonte bitmap, a exibição de Unicode pode quebrar; ao detectar isso, tenta trocar a fonte para Consolas ou Lucida Console
      • Um exemplo pode ser visto nesta photo
  • Melhorias de comportamento comuns

    • Fornece cores de 24 bits, convivência com redirecionamento de stdin/stdout/stderr e compatibilidade com arquivos de ajuda de 32 bits
    • Controla a taxa máxima de atualização com a variável de ambiente TVISION_MAX_FPS
      • O valor padrão é 60
      • 0 desativa o limite
      • -1 faz desenhar imediatamente a cada chamada de THardwareInfo::screenWrite
    • Suporta botão do meio do mouse, roda do mouse, tamanho de tela de até 32767 linhas/colunas e eventos de redimensionamento
    • As janelas podem ser redimensionadas também pelo canto inferior esquerdo, e áreas vazias podem ser arrastadas com o botão do meio
    • Menus podem ser fechados clicando novamente no item pai, e barras de rolagem respondem a rolagem por página e entrada da roda durante o arraste
    • TInputLine não rola o texto desnecessariamente ao mudar o foco
    • TFileViewer e TEditor suportam quebra de linha LF, e TEditor preserva a quebra de linha existente ao salvar, enquanto arquivos novos usam CRLF por padrão
    • TEditor inclui menu de clique com o botão direito, rolagem por arraste com o botão do meio, tecla de exclusão por palavra, melhorias na tecla Home e suporte a arquivos maiores que 64 KiB
    • tvdemo inclui um applet visualizador de eventos e uma opção para alterar o padrão de fundo

Loop de eventos e mudanças na API

  • Usa bufferização de escrita na tela e, em geral, envia ao terminal uma vez por iteração ativa do loop de eventos
  • Se for necessária atualização imediata em um loop ocupado, é possível chamar TScreen::flushScreen()
  • TEventQueue::waitForEvents(int timeoutMs) espera por eventos de entrada e, durante a espera, também atualiza a tela com TScreen::flushScreen()
  • TProgram::getEvent() chama isso com eventTimeoutMs, cujo padrão é 20, para evitar um loop ocupado com 100% de CPU
  • TEventQueue::wakeUp() é um método thread-safe para acordar o loop de eventos a partir de outra thread
  • TView::getEvent(TEvent &, int timeoutMs) permite espera com timeout no nível da view
  • setTimer e killTimer foram adicionados e geram evBroadcast e cmTimerExpired quando o timer expira
    • Se periodMs for negativo, o timer será de disparo único e será limpo automaticamente
    • Eventos de timer são gerados em TProgram::idle() e só são processados quando não há eventos de teclado ou mouse
  • TDrawBuffer não é mais um array de comprimento fixo e evita acessos fora dos limites
  • TRect em move, grow, intersect e Union retorna TRect&, permitindo encadeamento
  • TApplication fornece dosShell(), cascade() e tile() por padrão, e trata cmDosShell, cmCascade e cmTile por padrão
  • Foram adicionados tipos como TStringView, TSpan<T>, TDrawSurface, TSurfaceView e TClipboard
  • THardwareInfo, TScreen e TEventQueue são inicializados na criação da primeira TApplication, e não antes de main
  • As extensões de entrada também foram ampliadas
    • evMouseWheel, mwUp, mwDown, mwLeft, mwRight
    • mbMiddleButton, meTripleClick
    • evMouseUp.buttons mantém as informações dos botões liberados
    • hotKeyStr, getAltCharStr, getCtrlCharStr permitem implementar atalhos multibyte
    • TKey permite definir novas combinações de teclas como Shift+Alt+Up
    • TInputLine suporta limitMode de ilMaxBytes, ilMaxWidth e ilMaxChars

Integração com a área de transferência

  • Integração com a área de transferência do sistema

    • Antes, existia apenas uma área de transferência interna por meio do membro estático TEditor::clipboard, e só o TEditor podia usá-la
    • A nova classe TClipboard acessa a área de transferência do sistema e, se não puder acessá-la, usa a área de transferência interna como alternativa
  • Ambientes compatíveis

    • Compatível nativamente com Windows, WSL e macOS
    • Em Unix, exceto no macOS, é necessária uma dependência externa
    • Em execução remota, pode funcionar com X11 forwarding via ssh -X, far2l e putty4far2l, ou em terminais com suporte a OSC 52
    • Alguns outros terminais suportam apenas cópia
    • Colar com Ctrl+Shift+V ou Cmd+V no emulador de terminal continua sempre possível separadamente
  • API e tratamento de colagem

    • É possível usar TClipboard definindo Uses_TClipboard antes de incluir <tvision/tv.h>
    • setText(TStringView text) define o conteúdo da área de transferência do sistema e, se não houver acesso, usa a área de transferência interna
    • requestText() faz uma requisição assíncrona do conteúdo da área de transferência do sistema e depois o recebe no formato de um evento evKeyDown comum
    • O texto colado pode ser distinguido da entrada normal de teclado pela flag kbPaste em keyDown.controlKeyState
    • Para reduzir a ineficiência de colagens longas sendo processadas como milhares de teclas, foi adicionado TView::textEvent(...)
      • Lê o texto de evKeyDown consecutivos acumulando em um buffer do usuário
      • Quando deixar de ser texto, encaminha para o próximo loop com putEvent()
  • Integração com comandos padrão

    • TEditor e TInputLine respondem aos comandos cmCut, cmCopy, cmPaste
    • A aplicação deve vincular kbCtrlX, kbCtrlC, kbCtrlV a cada comando na barra de status ou equivalente
    • Os comandos relacionados são ativados ou desativados automaticamente conforme o foco e o estado da seleção

Modelo de cores estendido e compatibilidade

  • A API do Turbo Vision suporta cores estendidas além das 16 cores tradicionais
    • atributos de cor BIOS de 4 bits
    • RGB de 24 bits
    • índice de paleta xterm-256color de 8 bits
    • cor padrão do terminal
  • Se o terminal não suportar um formato específico de cor, o Turbo Vision faz a quantização para exibir
  • Em plataformas modernas, foram introduzidos TColorAttr no lugar de uchar e TAttrPair no lugar de ushort
    • TPalette também usa um array de TColorAttr
    • TView::mapColor passou a ser virtual, permitindo definir cores contornando o sistema hierárquico de paletas
  • TColorBIOS, TColorRGB, TColorXTerm, TColorDesired dividem a hierarquia de representação de cores
    • TColorAttr tem bitmasks de foreground, background e style
    • Os estilos incluem slBold, slItalic, slUnderline, slBlink, slReverse, slStrike
    • slReverse é pouco confiável, por isso recomenda-se usar reverseAttribute(TColorAttr attr)
  • Há três formas de usar cores estendidas em TView
    • sobrescrever mapColor e hardcodar por índice
    • passar TColorAttr diretamente para TDrawBuffer em draw()
    • modificar a própria paleta da aplicação
  • TScreen::screenMode expõe as capacidades de exibição
    • smMono é monocolor
    • smBW80 é grayscale
    • smCO80 é no mínimo 16 cores
    • smColor256 é no mínimo 256 cores
    • smColorHigh significa mais cores do que isso, por exemplo cores de 24 bits
  • A compatibilidade retroativa foi projetada para manter uma API comum sem #ifdef
    • No Borland C++, TColorAttr e TAttrPair são definidos por typedef como uchar e ushort, respectivamente
    • Em plataformas modernas, podem substituir os antigos uchar e ushort
    • Código legado continua compilando, mas atributos de cor não-BIOS podem se perder no momento em que forem convertidos implicitamente para uchar ou ushort
  • Código que usava ushort no método draw tanto para pares de índices de paleta quanto para pares de atributos de cor continua funcionando, mas para preservar as cores estendidas basta trocar a declaração da variável de ushort para TAttrPair
  • TColorDialog não foi redesenhado, então não pode ser usado como um seletor de cores estendidas em tempo de execução

Build, distribuição e integração

  • Linux e sistemas da família Unix

    • É possível compilar a biblioteca estática libtvision.a com CMake e GCC/Clang
    • hello, tvdemo, tvedit, tvdir, mmenu, palette e o Help Compiler tvhc também são gerados
    • Os requisitos são um compilador com suporte a C++14, libncursesw e o opcional libgpm
    • Para integração com a área de transferência em tempo de execução, são usados xsel, xclip e wl-clipboard
    • Em alguns ambientes, -ltinfow pode ser necessário; caso contrário, pode ocorrer segmentation fault durante a execução
      • Issue relacionada: #11
  • Windows e outras toolchains

    • O build com MSVC usa diretórios de build separados por arquitetura de destino, e os artefatos gerados são tvision.lib e apps de exemplo
    • A opção TV_USE_STATIC_RTL permite linkagem estática com o runtime da Microsoft
    • Não é possível misturar na linkagem binários /MT e /MD, nem binários de debug e não debug
    • Para usar <tvision/tv.h>, são necessárias as flags /permissive- e /Zc:__cplusplus; com o método de submódulo no CMake, isso é ativado automaticamente
    • Está indicado que, com a versão e a configuração adequadas do MSVC, Windows XP também é possível
    • O MinGW compila com CMake de forma semelhante ao Linux e, se o compilador suportar, pode rodar em Windows XP ou superior
    • Também é possível compilar bibliotecas para DOS ou Windows com Borland C++, mas não há suporte a Unicode
    • No ambiente Borland C++, o uso de winevdm é sugerido como alternativa
  • Formas de integração ao projeto e estado de distribuição

    • No CMake, são oferecidas duas formas: find_package(tvision CONFIG) ou add_subdirectory(tvision)
    • Em ambos os casos, os caminhos de include e os links necessários, como Ncurses e GPM, são tratados automaticamente
    • Existe um port tvision no vcpkg
    • No momento, não há stable release, e recomenda-se reportar problemas encontrados ao fazer upgrade com base nos commits mais recentes
    • Em sistemas da família Unix, é preciso compilar manualmente os apps de demonstração
    • Os binários para Windows são fornecidos em Actions
      • examples-dos32.zip: executáveis 32 bits compilados com Borland C++, sem suporte a Unicode
      • examples-x86.zip: executáveis 32 bits compilados com MSVC, requer Windows Vista ou superior
      • examples-x64.zip: executáveis 64 bits compilados com MSVC, requer Windows Vista x64 ou superior

Exemplos, documentação e casos de uso

1 comentários

 
GN⁺ 3 일 전
Comentários do Hacker News
  • Fiquei muito feliz de ver este repositório chegar à front page e, neste momento, estou fazendo eu mesmo um wrapper para ele
    Estou rodando o Turbo Vision no macOS sobre .NET, e a sensação é quase mágica
    Estou fornecendo uma API de nível mais alto, além de encapsular ou melhorar a API de palette, que já está bem antiquada, e também adicionando layout
    Ainda está tudo em um repositório privado em pleno desenvolvimento; hoje estou ajustando a palette com base na surface onde os controles foram colocados, amanhã lapido outra parte, e assim vou refinando continuamente
    Ainda faltam coisas como organizar o layout e adicionar controles básicos que fazem falta para os padrões de hoje
    Já usei Terminal.Gui antes, mas talvez por estar em transição para a v2, foi bem difícil lidar com ele sem bugs, e o Claude também mostrou muito bem o que não se deve fazer ao criar uma biblioteca TUI sem considerar um terminal real
    Então eu já vinha pensando que seria ótimo ter uma versão moderna do Turbo Vision, e aí encontrei este repositório; quando vi que ele ainda tinha suporte a Unicode, fiquei realmente grato

    • Oxygene faz parte da linha Elements, da RemObjects, então além do Oxygene da família Pascal, dá para misturar várias linguagens populares e levar isso para Windows, macOS, Linux, Android etc.
      https://www.remobjects.com/elements/oxygene/
      https://www.remobjects.com/elements/
    • Eu também já trabalhei com este port do tvision, e sempre que mexo em um novo framework TUI acabo sentindo que o lado do Turbo Vision é melhor
      Eu também estou fazendo um wrapper em .NET e, embora provavelmente esteja menos avançado, quero imitar o máximo possível a API do Windows Forms e até incluir um designer TUI com drag-and-drop
      O exemplo está aqui: https://github.com/brianluft/terminalforms/tree/main/src/TerminalFormsDemo
      A maior parte da integração complicada do lado de C++ foi resolvida aqui: https://github.com/brianluft/terminalforms/tree/main/src/tfcore
      Exportei funções C simples para que pudessem ser chamadas via P/Invoke, e deixei o lado em C# focado principalmente em organizar a estrutura de classes
      No começo, insisti na ideia de que tudo que fosse possível em C++ também deveria ser possível em C#, mas isso ficou complexo demais; cheguei ao ponto de colocar objetos C++ dentro de buffers de C# com placement new, praticamente como se estivesse herdando classes C++ do lado de C#, e o design desmoronou
      No fim, mudei para uma abordagem mais direta, menos flexível, mas muito mais simples, e decidi deixar a flexibilidade no lado do C#
      Fiquei curioso para saber como você estruturou o seu sistema de P/Invoke
    • Mexer com esta biblioteca TV dá uma boa dose de nostalgia, então é divertido
      Acho que isso me impediu de fazer tentativas inúteis, como criar aplicativos para GEOS ou entrar para a equipe de uma pessoa só do Hurd
    • Eu também queria tentar fazer a mesma coisa
      Cheguei a experimentar Terminal.Gui, mas o lado do TV me atrai mais, então já pensei em fazer um wrapper; adoraria ver isso quando for público
  • Minha carreira de programação literalmente começou numa caçamba de lixo nos anos 90
    Peguei um livro de Turbo Vision que alguém tinha jogado fora e me apaixonei imediatamente por aquela TUI azulada que qualquer um podia criar

  • A versão original vinha no Turbo Pascal 6, e o port para C++ apareceu depois
    Então isto pode ser visto como um port moderno de um port
    A Borland tinha outros frameworks parecidos nesse sentido: o OWL também começou primeiro no Turbo Pascal for Windows 1.5, e boa parte das ferramentas do C++ Builder na verdade foi escrita em Delphi
    O Object Pascal do Turbo Pascal 5.5, e depois o Turbo Vision do 6, foram minha porta de entrada para OOP, e sinto que tive sorte por ter começado por esse caminho
    Mesmo em um ambiente como o MS-DOS, dava para aprender muito bem as vantagens de frameworks trazidas por OOP e pelo Turbo Vision

    • O curioso é que o Free Vision é, em certo sentido, o resultado de alguém ter traduzido manualmente para Object/Free Pascal uma versão em C++ que, em algum momento, foi liberada em domínio público
    • O OWL estava realmente muito à frente do seu tempo
  • Quando a Borland lançou Turbo Pascal, Turbo C++, TurboVision, parecia que um universo de possibilidades se abria
    O desempenho dos compiladores era excelente e os manuais pareciam obras de arte; queria ainda ter aqueles livros
    Isso é simplesmente um tesouro cultural

    • Aqueles manuais eram realmente extraordinários
      No começo dos anos 90, aprendi C/C++ praticamente sozinho lendo só a pilha de livros da Borland que vinha com o Turbo C++; hoje em dia é difícil até imaginar uma cena dessas, de alguém aprendendo assim apenas com livros de referência
    • O Turbo Vision foi por muito tempo meu padrão-ouro
      Os frameworks TUI mais novos sempre pareciam ter alguma coisa faltando, e agora vou usá-lo de novo para verificar se isso era só nostalgia
      Pretendo colocá-lo na minha próxima ferramenta, e queria aplaudir muito quem fez isso
    • Houve uma época em que eu era Borland até o fim
      Tirando GW-BASIC e MS-DOS, era tudo Borland: Turbo BASIC, Turbo Pascal, Turbo C++ para MS-DOS e Windows 3.x, Turbo Vision, OWL
      Só fui usar VC++ lá pela versão 5, e o MFC sempre pareceu sem graça demais perto dos produtos da Borland
      Até hoje é raro ver algo que realmente acompanhe a capacidade RAD do C++ Builder, e mesmo o .NET levou bastante tempo para acertar a história de programação de baixo nível e AOT no estilo do Delphi
      Acho que desenvolvedores de Go, C++ e Rust deveriam receber algumas cópias do Turbo Pascal 7 para MS-DOS e do Delphi moderno
  • O Turbo Vision 2.0 ainda é bastante prático hoje; cheguei a usá-lo diretamente em um trabalho de prototipagem há cerca de um ano
    Tentei criar um frontend Turbo Vision para o depurador LLDB, para que funcionasse como o Turbo Debugger da Borland, e na maior parte deu certo
    Foi surpreendente sentir que ele continuava exatamente de onde parou em 199x, e também consegui compilar e executar código de 1993 sem grandes problemas
    Também existe uma versão melhor do editor interno, baseada em Scintilla, com recursos como syntax highlighting, mas as modificações que eu queria fazer não deram muito certo, então talvez eu precise pedir ajuda ao autor
    Porém, no sentido moderno de conhecimento compartilhado, falta documentação, então é difícil perguntar no Stack Overflow ou para uma IA; tive que aprender olhando o código de exemplo e relendo algumas vezes livros sobre Turbo Vision, do jeito antigo
    O layout manual é bem trabalhoso, então seria ótimo ter algo como o layout automático do Qt, e também sinto falta de splitter, embora não pareça difícil de implementar
    Outra coisa que me surpreendeu foi como o TV é, na prática, pequeno e compacto. Nos anos 90 ele parecia enorme
    No geral, o trabalho de modernização ficou realmente muito bom, e eu gosto muito disso

  • Ver um monte de diretivas do cmake me dá uma vontade estranha de voltar ao passado
    No Turbo C ou no Pascal, bastava apertar F9 e tudo rodava
    Por outro lado, sinto que isso também mostra a incompetência das nossas toolchains
    Hoje em dia, o ideal seria apontar para um compilador online e executar na hora, ou baixar, abrir uma pasta e rodar; em vez de ferramenta, isso virou quase um ritual

    • Em Unix moderno, compilar software já foi um problema resolvido
      ./configure && make && make install ainda deveria ser o gold standard
  • Este é só um dos ports/clones do Turbo Vision
    No lado de C++, também existe este aqui: https://github.com/kloczek/tvision
    A versão que entra no FreePascal/Lazarus foi escrita em Pascal, e também há uma em Rust que parece meio vibe-coded: https://github.com/aovestdipaperino/turbo-vision-4-rust

  • Rodando isso no terminal, perde-se um pouco da sensação essencial que o mouse na tela em modo texto costumava dar
    Numa tela real em modo texto, ele não parecia um ponteiro de mouse, mas sim um bloco amarelo movido pelo mouse
    Fico curioso se alguém já testou isso em modo texto Linux de alta resolução com GPM

    • Em essência, ele não era realmente amarelo
      Era mostrado invertendo as cores da célula sobre a qual estava, e como a janela principal que preenchia a maior parte da tela geralmente era azul-escura, muitas vezes o resultado parecia um bloco amarelo-claro
  • Recomendo um episódio recente do Wookash podcast sobre Chuck Jazdzewski
    Ele fez parte da equipe original que criou o Turbo Vision, e o episódio fala bastante sobre esse ecossistema como um todo

  • Eu ainda prefiro o Turbo Vision de verdade, ou seja, a versão em Pascal, em vez da versão em C++
    A de C++ sempre pareceu mais uma adaptação da de Pascal
    Por exemplo, em Pascal uses é uma palavra-chave, enquanto incluir módulos com #define sempre pareceu meio gambiarra
    Bem, talvez hoje isso já não faça tanta diferença

    • O Free Vision incluído no Free Pascal cumpre basicamente esse papel
      A IDE em modo texto também usa o Free Vision
      https://wiki.lazarus.freepascal.org/images/1/19/Userscreen.png
      Mas a principal diferença é que o Free Vision e o Turbo Vision usam o tipo object da época do Turbo Pascal 5.5, e não class do Delphi
      Com class, graças ao RTTI, fica fácil implementar coisas como serialização automática; já com object, isso não existe, então, para distinguir tipos diferentes em tempo de execução, é preciso fazer serialização manual, registrando o ponteiro VMT que fica em um offset fixo do ponteiro do objeto
      O Free Pascal até acrescentou algumas conveniências ao object, como private/protected/public e property, mas o Free Vision não usa essas extensões, porque ele implementa a API original do Turbo Vision