Delphi - drukarka Novitus i ActiveX OICFiscalPrinter

Delphi - drukarka Novitus i ActiveX OICFiscalPrinter
S8
  • Rejestracja:około 3 lata
  • Ostatnio:6 dni
  • Postów:62
0

Witam,

czy ktoś korzystał może z TOICFiscalPrinter do obsługi drukarki fiskalnej Novitus Online w Delphi i spotkał się może z dziwnym błędem AV przy zamykaniu aplikacji po tym jak stworzy się obiekt:

Kopiuj
FP:=TOICFiscalPrinter.Create(nil);

Może to coś komuś podpowie..

screenshot-20241029000525.png

edytowany 1x, ostatnio: flowCRANE
hzmzp
  • Rejestracja:ponad 11 lat
  • Ostatnio:około godziny
  • Postów:619
0

Podejrzewam że przed zamknięciem apki musisz wywołać coś takiego jak free czy close.
Choć ze screena wygląda że problem leży zupełnie w innym miejscu.

S8
  • Rejestracja:około 3 lata
  • Ostatnio:6 dni
  • Postów:62
0

dzięki ale to na pewno nie to, generalnie tutaj wskazuje na jakiś timer..ale ja nie widzę, żeby ten obiekt w ogóle był używany w jakimś timerze. Raczej liczę, że może ktoś używał tej samej biblioteki :) W świeżym projekcie utworzenie i zamknięcie nie powoduje błędu, może to kwestia jakiś ustawień kompilatora nawet :/ ciężko stwierdzić bo nie przenosi też oczywiście do fragmentu w kodzie w czasie debugowania.

DR
  • Rejestracja:9 miesięcy
  • Ostatnio:20 dni
  • Postów:14
1
Stl86 napisał(a):

czy ktoś korzystał może z TOICFiscalPrinter do obsługi drukarki fiskalnej Novitus Online w Delphi i spotkał się może z dziwnym błędem AV przy zamykaniu aplikacji

Ja korzystałem dla Novitus Delio Prime, aczkolwiek nie miałem błędów przy zamykaniu.

Przy zamykaniu aplikacji robiłem:

Kopiuj
if FP <> nil then
begin
  FP.Close;
  FreeAndNil(FP);
end;
flowCRANE
Moderator Delphi/Pascal
  • Rejestracja:ponad 13 lat
  • Ostatnio:3 minuty
  • Lokalizacja:Tuchów
  • Postów:12164
0

Nie znam tego API, ale czy parametrem konstruktora TOICFiscalPrinter.Create jest zwyczajny AOwner?

Jeśli tak, to zamiast podawać w nim nil, możesz podać jakiegokolwiek rodzica (formularz, albo i nawet Application) i taka instancja zostanie automatycznie zwolniona w destruktorze ownera, więc nie tylko zostanie wywołana raz, ale i nie będziesz musiał sam tego robić. Nie jestem zwolennikiem takich automatów (wolę sam alokować i dealokować), ale rób jak Ci wygodniej.

Przy czym zwróciłbym uwagę na to co napisał @Drunky, czyli na wywołanie metody Close przed Free. Choć obstawiam, że destruktor tej klasy sam woła Close, jeśli drukarka jest ”otwarta” w trakcie niszczenia jej instancji.

Natomiast aby znaleźć miejsce wystąpienia błędu AV, odpal aplikację pod debuggerem, do tego skorzystaj z narzędzi do analizowania pamięci, które oferuje Delphi. Gdzieś w kodzie jest odwołanie albo do znilowanego pointera, albo do nieprzydzielonej pamięci i stąd wyjątek.


Pracuję nad własną, arcade'ową, docelowo komercyjną grą z gatunku action/adventure w stylu retro (pixel art), programując silnik i powłokę gry od zupełnych podstaw, przy użyciu Free Pascala i SDL3. Więcej informacji znajdziesz na moim mikroblogu.
edytowany 3x, ostatnio: flowCRANE
S8
  • Rejestracja:około 3 lata
  • Ostatnio:6 dni
  • Postów:62
0

Próbowałem z ownerem też, właśnie to jest bardzo dziwna sytuacja tym bardziej, że to się pojawia nawet jeśli drukarka nie zostanie użyta w żaden sposób. Ja mam obawy, że problem jest w czymś innym niż sam ten obiekt :/

Zabawne jest to, że gdy przechodzę metodę Closę pod debuggerem , przechodząc linijka po linijce to się zamyka bez błędu..

edytowany 1x, ostatnio: Stl86
hzmzp
  • Rejestracja:ponad 11 lat
  • Ostatnio:około godziny
  • Postów:619
0

Daj cały call stack

flowCRANE
Moderator Delphi/Pascal
  • Rejestracja:ponad 13 lat
  • Ostatnio:3 minuty
  • Lokalizacja:Tuchów
  • Postów:12164
1
Stl86 napisał(a):

Ja mam obawy, że problem jest w czymś innym niż sam ten obiekt :/

Jak widać na zrzucie, błąd występuje w metodzie TTimer.WndProc, a więc wygląda na to, że wywala się kod timera, który odpowiedzialny jest za przechwytywanie zdarzeń WM_TIMER i odpalanie zdarzenia OnTimer. Więcej informacji jest tutaj — https://docwiki.embarcadero.com/CodeExamples/Alexandria/en/TTimerFWindowHandle_(Delphi). Jest tam nawet kod, który pokazuje jak to działa (usunąłem komentarze):

Kopiuj
procedure MyTTimer.WndProc(var Msg: TMessage);
begin
  with Msg do
    if Msg = WM_TIMER then // Check for timer messages.
      try
        Timer; // This calls the OnTimer event handler.
      except
        Application.HandleException(Self);
      end
    else
      Result := DefWindowProc(FWindowHandle, Msg, wParam, lParam);
end;

Tak więc albo wywala się kod timera, albo kod zdarzenia OnTimer.

Edit: tak szczerze pisząc, gdyby błąd dotyczył zdarzenia OnTimer, to byłoby ono widoczne w callstacku (wywołanie metody Timer też), a nie jest. Coś w tej metodzie odwołuje się do nieprzydzielonej lub już zwolnionej pamięci. Jedyne co mi przychodzi do głowy to to, że metoda WndProc lub Timer została wywołana na już zwolnionej instancji klasy TTimer. Ale w to trochę mi trudno uwierzyć, bo zniszczenie instancji timera wyrejestrowuje uchwyt okna (który timer sobie rejestruje w swoim konstruktorze), a więc po zniszczeniu timera ten uchwyt już nie istnieje (zostaje wyrejestrowany), więc system nie wyśle do niego komunikatu (czyli metoda WndProc się nie wykona).


Pracuję nad własną, arcade'ową, docelowo komercyjną grą z gatunku action/adventure w stylu retro (pixel art), programując silnik i powłokę gry od zupełnych podstaw, przy użyciu Free Pascala i SDL3. Więcej informacji znajdziesz na moim mikroblogu.
edytowany 2x, ostatnio: flowCRANE
S8
  • Rejestracja:około 3 lata
  • Ostatnio:6 dni
  • Postów:62
0

@hzmzp

Kopiuj
:01231695 TTimer.WndProc + $61
:010d57be StdWndProc + $16
:7693171b user32.AddClipboardFormatListener + 0x4b
:76927e8a ; C:\WINDOWS\SysWOW64\user32.dll
:76927a8a ; C:\WINDOWS\SysWOW64\user32.dll
:7692bf5f ; C:\WINDOWS\SysWOW64\user32.dll
:778154bd ntdll.KiUserCallbackDispatcher + 0x4d
:76925f8c user32.PostMessageW + 0x9c
:76926ba6 ; C:\WINDOWS\SysWOW64\user32.dll
:1e5a1f4a ; C:\Windows\SysWOW64\OICFiscalPrinterLib.ocx
:7693171b user32.AddClipboardFormatListener + 0x4b
:76927e8a ; C:\WINDOWS\SysWOW64\user32.dll
:76928da9 ; C:\WINDOWS\SysWOW64\user32.dll
:7692618d user32.SendMessageW + 0x4d
:1e5a7faa ; C:\Windows\SysWOW64\OICFiscalPrinterLib.ocx
:1e31abdd ; C:\Windows\SysWOW64\OICFiscalPrinterLib.ocx
:77812f96 ; 
:777ede52 ntdll.RtlActivateActivationContextUnsafeFast + 0xe2
:777fdba6 ; 
:777fda25 ntdll.RtlExitUserProcess + 0xb5
:756f6a53 KERNEL32.ExitProcess + 0x13
:00ffc8a6 @Halt0 + $116
:756efcc9 KERNEL32.BaseThreadInitThunk + 0x19
:7780809e ; 
:7780806e ntdll.RtlGetAppContainerNamedObjectPath + 0xee

edytowany 1x, ostatnio: Stl86
S8
  • Rejestracja:około 3 lata
  • Ostatnio:6 dni
  • Postów:62
0

Dzięki wszystkim za sugestie. Generalnie wyszło mi, że ten ActiveX gryzł się z jakimś timerem/wątkiem.. trudno powiedzieć bo nie udało mi się znaleźć bo sam w sobie też nasłuchiwał zdarzeń. Być może dałoby się to jakoś inaczej załatwić, gdzieś poczekać dłużej przy zamykaniu itd, ale ja zdecydowałem się na stworzenie tego obiektu w oddzielnym wątku i dać do niego dostęp z głównego i wygląda, że to załatwiło sprawę. Funkcjonalność zachowana, błędu przy zamykaniu nie ma.

edytowany 1x, ostatnio: Stl86
robertz68
  • Rejestracja:około 18 lat
  • Ostatnio:około godziny
  • Lokalizacja:Zielona Góra
1

od 15 lat korzystam z tego activeX z tym że ja nie tworzę obiektu a po prostu kładę komponent na formie.
Otwieram przez FP.Open a kończąc aplikację zamykam FP.Close.

Nie zauważyłem w tym czasie żadnych błędów a paragonów moje aplikacje wydrukowały ładnych parę milionów (a może więcej).

Według mnie drukowanie paragonów w osobnym wątku to nie jest dobry pomysł, jednak musisz mieć pełną wiedzę w jakim stanie jest urządzenie, czy na pewno paragon się wydrukował, czasami należy poczekać na założenie nowego papieru lub jakąś interakcję człowieka z drukarką itp. itd. Korzystanie z wątków może utrudniać przepływ tych informacji.

edytowany 1x, ostatnio: robertz68
S8
  • Rejestracja:około 3 lata
  • Ostatnio:6 dni
  • Postów:62
0

@robertz68 dzięki ale w tym przypadku nie ma różnicy czy to komponent położny na formę czy utworzony obiekt, problem jest taki sam. To jest akurat podstawowa obsługa tylko i na pewno nie żadna masowa produkcja paragonów. Ogólnie chodzi o użycie Novitus Online przez WiFi. Aplikacja obsługuje tez inne rodzaje drukarek, wiem, że lepiej by było używać tego w głównym wątku, w nowym projekcie oczywiście nie ma żadnych problemów z tym obiektem przy zamykaniu..ale niestety w tym z czymś się to gryzie. Nie mogę tego zlokalizować. To jest duża i wieloletnia aplikacja, gdzie nagle zaszła potrzeba obsługi tego Novitusa. Zdawałoby się, że prosta sprawa, obiekt fajnie spełnia swoje zadanie.. no ale ten błąd :/ To nawet z tym błędem (tylko przy zamykaniu aplikacji) sobie działa, drukuje..itd.
Mnie dziwi, że wystarczy utworzenie samego obiektu, nie trzeba nawet nic drukować, otwierać połączenia czy cokolwiek i już przy zamykaniu jest ten błąd. Ale jak się już debuguje zamykanie i robie step over manualnie do samego zamknięcia aplikacji to nie ma bledu..

flowCRANE
Moderator Delphi/Pascal
  • Rejestracja:ponad 13 lat
  • Ostatnio:3 minuty
  • Lokalizacja:Tuchów
  • Postów:12164
0

@Stl86: call stack pokazuje, że problem tkwi w kodzie timera. Może zamiast skupiać się na obsłudze drukarki, skup się na tych timerach — sprawdź jakie timery używane są w tym projekcie, do czego służą, co wykonują i jak są finalizowane.

Poza tym ta wielowątkowość zdaje się być nie tylko zbędna, ale i szkodliwa. Zasada jest prosta — jeśli coś może działać w ramach głównego wątku, to powinno w nim działać, a z wątków korzysta się wyłącznie wtedy, gdy jest to absolutnie konieczne (czyli nie można się obejść bez nich).


Pracuję nad własną, arcade'ową, docelowo komercyjną grą z gatunku action/adventure w stylu retro (pixel art), programując silnik i powłokę gry od zupełnych podstaw, przy użyciu Free Pascala i SDL3. Więcej informacji znajdziesz na moim mikroblogu.
edytowany 1x, ostatnio: flowCRANE
S8
  • Rejestracja:około 3 lata
  • Ostatnio:6 dni
  • Postów:62
0

@flowCRANE no tak tylko w call stacku widac tez ze jest zaangazowana akurat wtedy ta kontrolka.. w oogle to nawet nie chodzi o moment zamykania aplikacji, po prostu nawet jak
zrobię lokalna zmienna tej klasy , stworze ja i zaraz zniszczę, potem coś tam sobie porobię w programie to już wystarczy żeby przy zamknięciu wywaliło ten sam błąd co w 1 poście opisałem. Drukarka nawet nie jest podłączona.. leży w pudełku :)

edytowany 1x, ostatnio: Stl86
hzmzp
  • Rejestracja:ponad 11 lat
  • Ostatnio:około godziny
  • Postów:619
1

Wiesz, tak bez kodu to sobie możemy strzelać...

S8
  • Rejestracja:około 3 lata
  • Ostatnio:6 dni
  • Postów:62
0

No tak dlatego pytam czy może, ktoś się spotkał z czymś podobnym. Skoro nie;) to oznacza, że to wina leży w samej aplikacji i zapewne jakimś innym elemencie. Nie ma szans tu dać kodu. Od strony samego activeX sa 2 linijki. Wystarczy stworzyć i zniszczyć i juz.. jest problem przy zamykaniu. A reszta kodu.. to nie ma szans na wstawienie. To nie jest jakaś mała aplikacja tylko wielka , wieloletnia. Ja próbuje sobie to badać ale póki co bez jakiegoś sukcesu. Tak czy inaczej dzięki za rady.

flowCRANE
Moderator Delphi/Pascal
  • Rejestracja:ponad 13 lat
  • Ostatnio:3 minuty
  • Lokalizacja:Tuchów
  • Postów:12164
1

Zwykle, jeśli w dużym projekcie ma się z czymś poważny problem, to się ten problem izoluje od niego i testuje, a więc… Czy próbowałeś wykonać test na pustej aplikacji? Stwórz pusty projekt, a w nim dodaj tylko ten kod tworzący i niszczący drukarkę. Jeśli problem nadal będzie istnieć, to przynajmniej będziesz miał pewność, że za to nie jest odpowiedzialny kod Twojego projektu.


Pracuję nad własną, arcade'ową, docelowo komercyjną grą z gatunku action/adventure w stylu retro (pixel art), programując silnik i powłokę gry od zupełnych podstaw, przy użyciu Free Pascala i SDL3. Więcej informacji znajdziesz na moim mikroblogu.
S8
  • Rejestracja:około 3 lata
  • Ostatnio:6 dni
  • Postów:62
0

@flowCRANE , robiłem to. W pustym projekcie nie ma problemu. Dodawałem też do pustego projektu timery i też nie ma problemu. To pewnie coś bardziej pokręconego..

flowCRANE
Moderator Delphi/Pascal
  • Rejestracja:ponad 13 lat
  • Ostatnio:3 minuty
  • Lokalizacja:Tuchów
  • Postów:12164
0

Czyli wychodzi na to, że problem sprawia konkretnie kod Twojego projektu. Obstawiam, że jego kod jest własnościowy (zamknięto-źródłowy) i dlatego nie możesz pokazać źródeł. I tu jest problem, bo bez źródeł i konkretniejszej znajomości tego jak ten projekt działa, niewiele można Ci doradzić.


Pracuję nad własną, arcade'ową, docelowo komercyjną grą z gatunku action/adventure w stylu retro (pixel art), programując silnik i powłokę gry od zupełnych podstaw, przy użyciu Free Pascala i SDL3. Więcej informacji znajdziesz na moim mikroblogu.
S8
  • Rejestracja:około 3 lata
  • Ostatnio:6 dni
  • Postów:62
0

@flowCRANE dokładnie, ale też pokazanie kodu... to uwierz mi ze wiele godzin analiz by ktoś potrzebował. Używane tu są inne komponenty, zewnętrznych firm , rozne dllki itd itd. Pytałem w nadziei :) ze może ktoś się spotkał. Dziwi mnie to ze przechodząc debuggerem zamykanie aplikacji nie ma błędu..czyli jakby "reczne" opóźnienie całego procesu zamykania pomagało..

edytowany 1x, ostatnio: Stl86
flowCRANE
Moderator Delphi/Pascal
  • Rejestracja:ponad 13 lat
  • Ostatnio:3 minuty
  • Lokalizacja:Tuchów
  • Postów:12164
0

A jak to wygląda w release? Czy ten błąd powoduje np. pojawienie się systemowego okienka z błędem albo coś w tym stylu? Czy po prostu aplikacja zamyka się poprawnie, nie gubi żadnych danych itd. i nie powoduje szkód?


Pracuję nad własną, arcade'ową, docelowo komercyjną grą z gatunku action/adventure w stylu retro (pixel art), programując silnik i powłokę gry od zupełnych podstaw, przy użyciu Free Pascala i SDL3. Więcej informacji znajdziesz na moim mikroblogu.
S8
  • Rejestracja:około 3 lata
  • Ostatnio:6 dni
  • Postów:62
0

W release nie ma nic, żadnego komunikatu, nic to nie przeszkadza. Ja myślę, że to jest coś nieistotnego.. no ale to lipa taki błąd zostawić. W tym wątku przynajmniej nie widać ;P
Ale ten wątek to jest tak, że ja tam tworze tylko statyczny obiekt ( jako class var) i to wszystko, tam nic więcej się nie dzieje, a w głównym wątku sobie przypisuje go zmiennej i tyle i używam tak samo jakbym stworzył w głównym wątku.

robertz68
  • Rejestracja:około 18 lat
  • Ostatnio:około godziny
  • Lokalizacja:Zielona Góra
3
Stl86 napisał(a):

@flowCRANE Dziwi mnie to ze przechodząc debuggerem zamykanie aplikacji nie ma błędu..czyli jakby "reczne" opóźnienie całego procesu zamykania pomagało..

i tu jest zapewne sedno twojego problemu. Sam piszesz że aplikacja używa dll-ek itp. Ja właśnie obstawiam na czas potrzebny na zamknięcie wszystkich otwartych elementów aplikacji. Po prostu tego czasu nie wystarcza.

Podobną sytuację miałem z aplikacją używającą sfery Subiekta. Taki program startując uruchamia w tle Subiekta (a to trwa), następnie przy kończeniu aplikacji Subiekt jest zamykany i to trwa jeszcze dłużej. Wymyśliłem sobie że z różnych względów raz na dobę będę restartował program i zrobiły się problemy. Na moim szybkim komputerze problemu nie zauważyłem ale u klienta na kilkuletnim serwerze z macierzą dysków HDD SAS wydajność tego systemu nie wystarczyła aby zamknąć Subiekta przed ponowną jego próbą uruchomienia.

Tak więc przyjrzyj się tej kwestii albo jakoś sztucznie opóźnij zamykanie aplikacji.

S8
  • Rejestracja:około 3 lata
  • Ostatnio:6 dni
  • Postów:62
0

Wydaje mi się, że rozwiązałem ten problem, przejrzałem jeszcze kwestie niszczenia roznych obiektow i wydaje mi sie ze to nie bylo dopilnowane, w tym timery tworzone dynamicznie (chociaz robilem taki test na czystym projekcie i nie było błędów). W każdym razie poprawiłem to masowo wszystko w desktruktorach klas i wydaje sie ze to załatwiło sprawę. Dziękuję wszystkim za sugestie i chęć pomocy.

flowCRANE
Moderator Delphi/Pascal
  • Rejestracja:ponad 13 lat
  • Ostatnio:3 minuty
  • Lokalizacja:Tuchów
  • Postów:12164
2

W razie czego, pamiętaj, że nawet jeśli zapomnisz zwolnić dynamicznie stworzonych obiektów, to nic się nie stanie, dlatego że system operacyjny posprząta wszystko po tym, gdy proces zakończy działanie — zwolni całą zarezerwowaną przez niego pamięć (ewentualnie łącznie z tą, która wyciekła), pozamyka niezamknięte uchwyty i zwolni wszelkie inne niesfinalizowane zasoby. Robi to i musi to robić, aby utrzymać swoją stabilność.

Tak więc brak jawnego zwolnienia dynamicznie zaalokowanych zasobów poważnym problemem nie jest, a jedynie to, że w trakcie zamykania procesu mogą próbować jeszcze robić coś, co ostatecznie doprowadza do błędu/wyjątku. Skup się na razie na tym, aby tego nie robiły (czyli wyklucz pojawianie się błędu w debugu), natomiast niezwolnione zasoby zawsze możesz łatwo namierzyć za pomocą dedykowanych narzędzi i dodać kod ich finalizacji.


Pracuję nad własną, arcade'ową, docelowo komercyjną grą z gatunku action/adventure w stylu retro (pixel art), programując silnik i powłokę gry od zupełnych podstaw, przy użyciu Free Pascala i SDL3. Więcej informacji znajdziesz na moim mikroblogu.
edytowany 3x, ostatnio: flowCRANE
S8
  • Rejestracja:około 3 lata
  • Ostatnio:6 dni
  • Postów:62
0

Tak wiem ale jednak etyka pracy nie pozwala mi zostawić takiego błędu. Ale już jest OK. Obiekt tworzony w wątku głównym, drukarka drukuje, błędu przy zamykaniu nie ma. Dzięki @flowCRANE i @robertz68. Myślę, że możemy zakończyć wątek :)

flowCRANE
Wszystkie błędy muszą być naprawione. Podoba mi się takie podejście, w pełni popieram. ;)
Kliknij, aby dodać treść...

Pomoc 1.18.8

Typografia

Edytor obsługuje składnie Markdown, w której pojedynczy akcent *kursywa* oraz _kursywa_ to pochylenie. Z kolei podwójny akcent **pogrubienie** oraz __pogrubienie__ to pogrubienie. Dodanie znaczników ~~strike~~ to przekreślenie.

Możesz dodać formatowanie komendami , , oraz .

Ponieważ dekoracja podkreślenia jest przeznaczona na linki, markdown nie zawiera specjalnej składni dla podkreślenia. Dlatego by dodać podkreślenie, użyj <u>underline</u>.

Komendy formatujące reagują na skróty klawiszowe: Ctrl+B, Ctrl+I, Ctrl+U oraz Ctrl+S.

Linki

By dodać link w edytorze użyj komendy lub użyj składni [title](link). URL umieszczony w linku lub nawet URL umieszczony bezpośrednio w tekście będzie aktywny i klikalny.

Jeżeli chcesz, możesz samodzielnie dodać link: <a href="link">title</a>.

Wewnętrzne odnośniki

Możesz umieścić odnośnik do wewnętrznej podstrony, używając następującej składni: [[Delphi/Kompendium]] lub [[Delphi/Kompendium|kliknij, aby przejść do kompendium]]. Odnośniki mogą prowadzić do Forum 4programmers.net lub np. do Kompendium.

Wspomnienia użytkowników

By wspomnieć użytkownika forum, wpisz w formularzu znak @. Zobaczysz okienko samouzupełniające nazwy użytkowników. Samouzupełnienie dobierze odpowiedni format wspomnienia, zależnie od tego czy w nazwie użytkownika znajduje się spacja.

Znaczniki HTML

Dozwolone jest używanie niektórych znaczników HTML: <a>, <b>, <i>, <kbd>, <del>, <strong>, <dfn>, <pre>, <blockquote>, <hr/>, <sub>, <sup> oraz <img/>.

Skróty klawiszowe

Dodaj kombinację klawiszy komendą notacji klawiszy lub skrótem klawiszowym Alt+K.

Reprezentuj kombinacje klawiszowe używając taga <kbd>. Oddziel od siebie klawisze znakiem plus, np <kbd>Alt+Tab</kbd>.

Indeks górny oraz dolny

Przykład: wpisując H<sub>2</sub>O i m<sup>2</sup> otrzymasz: H2O i m2.

Składnia Tex

By precyzyjnie wyrazić działanie matematyczne, użyj składni Tex.

<tex>arcctg(x) = argtan(\frac{1}{x}) = arcsin(\frac{1}{\sqrt{1+x^2}})</tex>

Kod źródłowy

Krótkie fragmenty kodu

Wszelkie jednolinijkowe instrukcje języka programowania powinny być zawarte pomiędzy obróconymi apostrofami: `kod instrukcji` lub ``console.log(`string`);``.

Kod wielolinijkowy

Dodaj fragment kodu komendą . Fragmenty kodu zajmujące całą lub więcej linijek powinny być umieszczone w wielolinijkowym fragmencie kodu. Znaczniki ``` lub ~~~ umożliwiają kolorowanie różnych języków programowania. Możemy nadać nazwę języka programowania używając auto-uzupełnienia, kod został pokolorowany używając konkretnych ustawień kolorowania składni:

```javascript
document.write('Hello World');
```

Możesz zaznaczyć również już wklejony kod w edytorze, i użyć komendy  by zamienić go w kod. Użyj kombinacji Ctrl+`, by dodać fragment kodu bez oznaczników języka.

Tabelki

Dodaj przykładową tabelkę używając komendy . Przykładowa tabelka składa się z dwóch kolumn, nagłówka i jednego wiersza.

Wygeneruj tabelkę na podstawie szablonu. Oddziel komórki separatorem ; lub |, a następnie zaznacz szablonu.

nazwisko;dziedzina;odkrycie
Pitagoras;mathematics;Pythagorean Theorem
Albert Einstein;physics;General Relativity
Marie Curie, Pierre Curie;chemistry;Radium, Polonium

Użyj komendy by zamienić zaznaczony szablon na tabelkę Markdown.

Lista uporządkowana i nieuporządkowana

Możliwe jest tworzenie listy numerowanych oraz wypunktowanych. Wystarczy, że pierwszym znakiem linii będzie * lub - dla listy nieuporządkowanej oraz 1. dla listy uporządkowanej.

Użyj komendy by dodać listę uporządkowaną.

1. Lista numerowana
2. Lista numerowana

Użyj komendy by dodać listę nieuporządkowaną.

* Lista wypunktowana
* Lista wypunktowana
** Lista wypunktowana (drugi poziom)

Składnia Markdown

Edytor obsługuje składnię Markdown, która składa się ze znaków specjalnych. Dostępne komendy, jak formatowanie , dodanie tabelki lub fragmentu kodu są w pewnym sensie świadome otaczającej jej składni, i postarają się unikać uszkodzenia jej.

Dla przykładu, używając tylko dostępnych komend, nie możemy dodać formatowania pogrubienia do kodu wielolinijkowego, albo dodać listy do tabelki - mogłoby to doprowadzić do uszkodzenia składni.

W pewnych odosobnionych przypadkach brak nowej linii przed elementami markdown również mógłby uszkodzić składnie, dlatego edytor dodaje brakujące nowe linie. Dla przykładu, dodanie formatowania pochylenia zaraz po tabelce, mogłoby zostać błędne zinterpretowane, więc edytor doda oddzielającą nową linię pomiędzy tabelką, a pochyleniem.

Skróty klawiszowe

Skróty formatujące, kiedy w edytorze znajduje się pojedynczy kursor, wstawiają sformatowany tekst przykładowy. Jeśli w edytorze znajduje się zaznaczenie (słowo, linijka, paragraf), wtedy zaznaczenie zostaje sformatowane.

  • Ctrl+B - dodaj pogrubienie lub pogrub zaznaczenie
  • Ctrl+I - dodaj pochylenie lub pochyl zaznaczenie
  • Ctrl+U - dodaj podkreślenie lub podkreśl zaznaczenie
  • Ctrl+S - dodaj przekreślenie lub przekreśl zaznaczenie

Notacja Klawiszy

  • Alt+K - dodaj notację klawiszy

Fragment kodu bez oznacznika

  • Alt+C - dodaj pusty fragment kodu

Skróty operujące na kodzie i linijkach:

  • Alt+L - zaznaczenie całej linii
  • Alt+, Alt+ - przeniesienie linijki w której znajduje się kursor w górę/dół.
  • Tab/⌘+] - dodaj wcięcie (wcięcie w prawo)
  • Shit+Tab/⌘+[ - usunięcie wcięcia (wycięcie w lewo)

Dodawanie postów:

  • Ctrl+Enter - dodaj post
  • ⌘+Enter - dodaj post (MacOS)