Wyświetlenie ścieżki programu bez nawy pliku

Wyświetlenie ścieżki programu bez nawy pliku
0

Czy ten program który napisałem jest poprawny? Jak można by go bardziej skrócić?

Kopiuj
#include <iostream>
#include <windows.h>

using namespace std;

int main(){
	char filename[MAX_PATH];	
	GetModuleFileName(NULL, filename, MAX_PATH);
	const BYTE* lpData = (const BYTE*)filename;
	
	string _file(filename), folder, folder_;

	for (int i = _file.size(); i > -1; --i)
		if (_file[i] == 0x5C)
			for(i; i > -1; --i)
				folder += _file[i];

	for (int i = fol.size()-1; i > -1; --i)
		folder_ += folder[i];
	
	cout<<folder_;
}
_13th_Dragon
  • Rejestracja:ponad 19 lat
  • Ostatnio:2 miesiące
1
Kopiuj
#include <string>
#include <iostream>
using namespace std;
 
int main(int argc,char *argv[])
  {
   string path(argv[0]);
   path.erase(path.find_last_of("\\/"));
   cout<<path<<endl;
   return 0;
  }

Ba, zadziała pod linuksem również.


Wykonuję programy na zamówienie, pisać na Priv.
Asm/C/C++/Pascal/Delphi/Java/C#/PHP/JS oraz inne języki.
edytowany 1x, ostatnio: _13th_Dragon
1

Ten kod zadziała tylko jeśli program jest uruchomiony z ścieżka lub poprzez dwuklik ale jeśli się uruchomi go poprzez podanie nazwy to program się wykrzaczy dlatego wolałbym kod bez argv[0] :)

user image

0

Dzięki za przykładowy kod udało mi się już poprawić swój :)

user image

Patryk27
Moderator
  • Rejestracja:ponad 17 lat
  • Ostatnio:ponad rok
  • Lokalizacja:Wrocław
  • Postów:13042
0

ale jeśli się uruchomi go poprzez podanie nazwy
Poprzez co? :|


1
Patryk27 napisał(a):

ale jeśli się uruchomi go poprzez podanie nazwy
Poprzez co? :|

Tutaj chodzi, że jeśli wpiszę tylko samą nazwę pliku w wierszu poleceń to program przestaje odpowiadać i nie działa jak należy.

_13th_Dragon
  • Rejestracja:ponad 19 lat
  • Ostatnio:2 miesiące
1

Problem w tym że GetModuleFileName ogranicza cię tylko do windows.
Więc zawsze możesz zaradzić w ten sposób:

Kopiuj
#include <string>
#include <iostream>
using namespace std;
 
int main(int argc,char *argv[])
  {
   string path(argv[0]);
   size_t pos=path.find_last_of("\\/");
   if(pos==string::npos) path=".";
   else path.erase(pos);
   cout<<path<<endl;
   return 0;
  }

Ewentualnie:

Kopiuj
#include <string>
#include <iostream>
#include <windows.h>
using namespace std;
 
int main(int argc,char *argv[])
  {
   string path(MAX_PATH+1,'\0');
   path.resize(GetModuleFileName(0,&path[0],MAX_PATH));
   path.erase(path.find_last_of("\\/"));
   cout<<path<<endl;
   return 0;
  }

Wykonuję programy na zamówienie, pisać na Priv.
Asm/C/C++/Pascal/Delphi/Java/C#/PHP/JS oraz inne języki.
edytowany 1x, ostatnio: _13th_Dragon
vpiotr
  • Rejestracja:ponad 13 lat
  • Ostatnio:prawie 3 lata
0

Wersja z obsluga nazwy bez sciezki:

Kopiuj
#include <string>
#include <iostream>
using namespace std;
 
int main(int argc,char *argv[])
  {
   string path(argv[0]);
   size_t pos = path.find_last_of("\\/");
   if (pos != string::npos)
     path.erase(pos);
   else
     path = "";
   cout<<path<<endl;
   return 0;
  }
edytowany 1x, ostatnio: vpiotr
Zobacz pozostały 1 komentarz
vpiotr
tam jest jeden drobny blad - mix Pascala i C. I dyskusyjne jest zwracanie "path" = "." ( nie wiem czy o to chodzilo OP).
_13th_Dragon
Jak brak ścieżki w argv to ścieżką jest ścieżka bieżąca, czyli pod windows: ".\" pod linuxem "./" a że zwracamy bez końcowej łamanej to jest bez końcowej czyli sama kropka. Natomiast nazwa exe zamiast path to na 100% nie o to chodziło OP. Co do błędu - po pierwsze, dotyczy drugiej części czyli innego przypadku; po drugie, jest zagwarantowane że obszar jest ciągły - owszem nie jest zagwarantowany los zmiennych typu string z których skopiowaliśmy ten path, a że z niczego nie był kopiowany - to nie ma żadnych obaw.
vpiotr
blad jest w tej samej linii co kropka.
_13th_Dragon
O rzesz, to trzeba takie rzeczy w komentarzu dawać pod postem.
vpiotr
a kropki nie lubie (magic value) wiec pozostane przy swojej wariacji.
0

Ok. Dzięki za pomoc :)

Gynvael Coldwind
  • Rejestracja:ponad 21 lat
  • Ostatnio:7 dni
  • Lokalizacja:Zurich, Switzerland
  • Postów:457
34

Dopiszę kilka rzeczy, bo widzę, że jest parę nie do końca poprawnych przekonań napisanych wyżej ;)

_13th_Dragon napisał(a)

Jak brak ścieżki w argv to ścieżką jest ścieżka bieżąca, czyli pod windows: ".\" pod linuxem "./" a że zwracamy bez końcowej łamanej to jest bez końcowej czyli sama kropka.

To nie jest niestety prawdziwe stwierdzenie - plik wykonywalny może być równie dobrze w dowolnym miejscu wskazanym przez zmienną środowiskową PATH. Dla przykładu załóżmy, że mamy następujący kod:

Kopiuj
#include <stdio.h>

int main(int argc, char **argv) {
  int i;

  printf("argc: %i\n", argc);
  for(i = 0; i < argc; i++) {
    printf("argv[%i]: %s\n", i, argv[i]);
  }

  return 0;
}

Uruchomienie z cwd i katalogu w PATH pod Windows:

Kopiuj
gynvael:haven-windows> test.exe
argc: 1
argv[0]: test.exe

gynvael:haven-windows> mkdir asdf

gynvael:haven-windows> move test.exe asdf
        1 file(s) moved.

gynvael:haven-windows> set path=asdf;%path%

gynvael:haven-windows> test
argc: 1
argv[0]: test

Jak widać argv[0] nie zawiera ścieżki. Co więcej, argv[0] nie zawiera również rozszerzenia.
Ah, i jak widać wrzuciłem sobie do PATH ścieżkę relatywną - zazwyczaj powinno się wrzucać bezwzględną, ale na potrzeby eksperymentu to wystarczy.

A teraz to samo pod Ubuntu (przy czym zostawiłem nazwę exeka "a.out', ponieważ bash posiada wbudowane polecenie o nazwie test, a jeśli się nie poda ścieżki, to przez bash preferowane jest polecenie wbudowane):

Kopiuj
10:30:56 gynvael:haven-linux> gcc test.c
10:31:01 gynvael:haven-linux> ./a.out 
argc: 1
argv[0]: ./a.out
10:31:03 gynvael:haven-linux> mv a.out asdf
10:31:06 gynvael:haven-linux> export PATH=asdf:$PATH
10:31:18 gynvael:haven-linux> a.out
argc: 1
argv[0]: a.out

Aby trochę sprecyzować, argv[0] niekoniecznie musi zawierać ścieżkę do (czy nawet pełną nazwę) exeka; argv[0] zawiera informacje o tym jak program został wywołany.

Kilka losowych przykładów jeszcze.

  1. Linki symboliczne:
Kopiuj
10:34:37 gynvael:haven-linux> ln -s ./asdf/a.out frrr
10:34:49 gynvael:haven-linux> ./frrr
argc: 1
argv[0]: ./frrr
10:34:55 gynvael:haven-linux> ls -la frrr
lrwxrwxrwx 1 gynvael gynvael 12 Mar  9 10:34 frrr -> ./asdf/a.out

Exek się oczywiście nie nazywa "frrr", ale tak został wywołany, więc taką informację Bash przekazał do procesu potomnego.
Z tego zachowania korzysta trochę poleceń pod Unixami btw, które mają jeden plik wykonywalny, ale zachowują się różnie w zależności od tego przez który link zostały wywołane (idealnym przykładem jest busybox).

  1. Nic-co-by-było-związane-z-czymkolwiek-sensownym w argv[0]
    Pod Ubuntu zawartość argv[0] całkowicie kontroluje proces-rodzic, więc nie musi tam być absolutnie nic związanego z tym co jest wywoływane. Rozważmy następujący kod:
Kopiuj
#include <unistd.h>

int main(int argc, char **argv, char **envp) {
  char * new_argv[] = {
    "ala ma kota kot ma ale", // argv[0]
    NULL
  };

  execve("/tmp/asdf/a.out", new_argv, envp);

  return 0;
}

EDIT
Mieliśmy z @KrzaQ krótką dyskusje o tym czemu zrobiłem coś tak głupiego jak przypisanie literału tekstowego do char*, więc krótkie wyjaśnienie: jak najbardziej zdaje sobie sprawę, że w C domyślnie literały są const i kompilator może je wrzucić do pamięci read-only (co więcej, jak @KrzaQ wskazał, kompilator może różne literały połączyć w pamięci w jeden - np. zamiast osobno wrzucać "foobar" i "bar", wrzucić tylko "foobar", bo ten zawiera "bar" w sobie). Natomiast tutaj jest jeszcze jeden czynnik - execve z losowych powodów wymaga char* a nie const char*, mimo, iż jest gwarancja, iż char* nigdy nie zostanie zmodyfikowany (mowa cały czas o pojedynczym elemencie argv[]) - vide http://pubs.opengroup.org/onlinepubs/9699919799/functions/exec.html . Ja natomiast byłem trochę leniwy i nie chciało mi się w kodzie wyżej robić rzutowania, więc od razu zrobiłem char* - to przejdzie w przypadku eksperymentu, ale w kodzie produkcyjnym ofc lepiej tak nie robić. Przy czym, jeszcze trzy rzeczy:

  • "writable string literals" jest wymienione w standardzie C11 jako "common extension", więc niektóre kompilatory mogą domyślnie robić zapisywalne literały, ew. może być opcja by takie zrobić (np. @KrzaQ wskazał -fwritable-strings z GCC; w dokumentacji jest fajny dopisek btw: "Writing into string constants is a very bad idea; "constants" should be constant.")
  • może się okazać, że kompilator (przy normalnych zachowaniu) wrzuci string literal do sekcji .rdata (read-only data), która z założenia jest tylko do odczytu, ale, z uwagi na układ sekcji, .rdata trafi do pamięci mimo wszystko zapisywalnej (bardzo rzadkie, ale chyba widziałem coś takiego) albo wykonywalnej - to akurat dość częste w przypadku GCC na Ubuntu.
  • nie wiem jak jest teraz, ale jeszcze parę lat temu jak się spakowało exeka UPXem, to ten zmieniał wszystkie rzeczy tylko-do-odczytu na read-write-execute, co bardzo ułatwiało exploitacje ;)
    KONIEC EDIT

Kompilacja i uruchomienie:

Kopiuj
10:36:58 gynvael:haven-linux> gcc run.c 
10:38:29 gynvael:haven-linux> ./a.out 
argc: 1
argv[0]: ala ma kota kot ma ale

Co więcej, pod Windowsem jest dokładnie tak samo ;)

Kopiuj
#include <windows.h>

int main(void) {
  PROCESS_INFORMATION pi;
  STARTUPINFO si = { sizeof(STARTUPINFO) };

  CreateProcess(
      "asdf\\test.exe",
      "ala ma kota kot ma ale", // Command line
      NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi);

  WaitForSingleObject(pi.hProcess, 1000);
  CloseHandle(pi.hProcess);
  CloseHandle(pi.hThread);  
  return 0;
}
Kopiuj
gynvael:haven-windows> gcc runwin.c -o runwin

gynvael:haven-windows> runwin
argc: 6
argv[0]: ala
argv[1]: ma
argv[2]: kota
argv[3]: kot
argv[4]: ma
argv[5]: ale

Ciekawostka: A magia to się zaczyna dopiero dziać, jak się da "*" jako command line ;)

Kopiuj
gynvael:haven-windows> runwin
argc: 5
argv[0]: .runwin.c.swp
argv[1]: asdf
argv[2]: runwin.c
argv[3]: runwin.exe
argv[4]: test.c

Przy czym to akurat specyfika domyślnego zachowania prologu kompilatora MinGW, która rozwija symbole wieloznaczne (*, ?) w argv[] (łącznie z argv[0]) do listy plików spełniających określony pattern (jeśli ktoś ma moją książkę, to coś więcej napisałem o tym na stronie 340 w ramce "Argumenty main i rozwinięcie symboli wieloznacznych [VERBOSE]"; a jeśli ktoś nie ma, to szybkie info: aby to wyłączyć w MinGW trzeba w programie mieć zmienną globalną int _CRT_glob=0, natomiast aby to włączyć w MSVC, trzea zlinkować z plikiem setargv.obj lub wsetargv.obj).

W ramach ciekawostki jeszcze dodam, że MAXPATH (~259 znaków) wystarczy w 99.999% przypadków, natomiast pod Windowsem ścieżki mogą mieć do 32K znaków (vide http://www.icewall.pl/?p=467).

Na zakończenie jeszcze info jak pobrać nazwę i ścieżkę pliku wykonywalnego pod Ubuntu:

Kopiuj
#include <stdio.h>
#include <unistd.h>

int main(void) {
  // Readlink nie dodaje \0, wiec buf powinien byc wyzerowany.
  char exe_name[4096] = {0};  
  readlink("/proc/self/exe", exe_name, sizeof(exe_name) - 1);

  printf("exe: %s\n", exe_name);

  return 0;
}
Kopiuj
10:58:46 gynvael:haven-linux> gcc getname.c 
10:58:49 gynvael:haven-linux> ./a.out 
exe: /tmp/a.out

I jeszcze jedna ciekawostka (kudos jagger) - /proc/self/exe nie do końca jest linkiem ;)
Okazuje się, że nawet jeśli usuniemy plik wykonywalny (a proces nadal będzie chodzić ofc), to po /proc/self/exe nadal dostaniemy się do pliku wykonywalnego, pomimo tego, iż ls będzie twierdzić, że docelowy plik został usunięty. Np.

Kopiuj
11:01:24 gynvael:haven-linux> cp /bin/cat /tmp/xxx
11:01:29 gynvael:haven-linux> ./xxx
^Z
[1]+  Stopped                 ./xxx

11:01:39 gynvael:haven-linux> rm xxx

11:01:46 gynvael:haven-linux> ls -la xxx
ls: cannot access xxx: No such file or directory

11:01:54 gynvael:haven-linux> ps aux | grep xxx | grep -v grep
gynvael  19605  0.0  0.0   7212   360 pts/13   T    11:01   0:00 ./xxx

11:02:03 gynvael:haven-linux> ls -la /proc/19605/exe
lrwxrwxrwx 1 gynvael gynvael 0 Mar  9 11:02 /proc/19605/exe -> /tmp/xxx (deleted)

11:02:14 gynvael:haven-linux> cat /proc/19605/exe | hexdump -C | head
00000000  7f 45 4c 46 02 01 01 00  00 00 00 00 00 00 00 00  |.ELF............|
00000010  02 00 3e 00 01 00 00 00  02 26 40 00 00 00 00 00  |..>......&@.....|
00000020  40 00 00 00 00 00 00 00  20 b4 00 00 00 00 00 00  |@....... .......|
00000030  00 00 00 00 40 00 38 00  09 00 40 00 1c 00 1b 00  |....@.8...@.....|
00000040  06 00 00 00 05 00 00 00  40 00 00 00 00 00 00 00  |........@.......|
00000050  40 00 40 00 00 00 00 00  40 00 40 00 00 00 00 00  |@.@.....@.@.....|
00000060  f8 01 00 00 00 00 00 00  f8 01 00 00 00 00 00 00  |................|
00000070  08 00 00 00 00 00 00 00  03 00 00 00 04 00 00 00  |................|
00000080  38 02 00 00 00 00 00 00  38 02 40 00 00 00 00 00  |8.......8.@.....|
00000090  38 02 40 00 00 00 00 00  1c 00 00 00 00 00 00 00  |8.@.............|

11:02:35 gynvael:haven-linux> killall -9 xxx
[1]+  Killed                  ./xxx

11:02:46 gynvael:haven-linux> 

Nyom.


peace,
gynvael.coldwind//vx "Imagination is more important than knowledge..." Albert Einstein
edytowany 8x, ostatnio: Gynvael Coldwind
Zobacz pozostałe 2 komentarze
Gynvael Coldwind
@Afish: Hmmm afair jeśli się używa formy root local device (vide http://googleprojectzero.blogspot.ch/2016/02/the-definitive-guide-on-win32-to-nt.html) to niektóre WinAPI działają (ale tak jak piszesz - nie wszystkie). NT API natomiast ogarnia wszystko, przy czym tam ścieżki się trochę inaczej zachowują (vide link wcześniej) @fasadin :)
AL
@Gynvael Coldwind odnośnie const stringów, stałości argv itd. to dorzuć jeszcze to: http://stackoverflow.com/questions/963493/is-it-possible-to-change-argv-or-do-i-need-to-create-an-adjusted-copy-of-it sam to w pracy ćwiczyłem niedawno ;) btw z narzędzi czułych na nazwę polecenia to chyba grep i wariacje typu egrep są najpopularniejsze ;)
Gynvael Coldwind
@alagner: ciekawy link :) warto dodać, że zmiana pamięci na którą wskazuje argv[0], etc jest pod Ubuntu/etc widoczna na zewnątrz procesu w /proc/PID/cmdline, z którego korzysta między innym ps aux - można więc sobie zmienić to-na-co-wskazuje-argv[0] na cokolwiek (z dokładnością do wielkości tego bufora ofc) po uruchomieniu programu i wtedy nagle ps aux będzie widział proces pod inną nazwą (choć /proc/PID/exe nadal będzie wskazywać na oryginalny exe) ;)
AL
@Gynvael Coldwind to jest jakieś specyficzne dla ubuntu działanie? Nie mam w domu ani pracy ubunciaka, ale w wolnej chwili porobię chyba testy na paru innych systemach...
Gynvael Coldwind
@alagner: Chyba nie - sądzę, że to typowe dla Linuxów ogólnie, natomiast testowałem tylko na Ubuntu. Jeśli byś robił testy, daj znać jak tam wyniki (szczególnie ciekawe byłoby sprawdzenie na innych Unixach-nie-będących-Linuxami ;>).
vpiotr
  • Rejestracja:ponad 13 lat
  • Ostatnio:prawie 3 lata
0

No dobra, skoro już piszemy jak to się robi na prawdę, to dodam coś od siebie:

Kopiuj
/// Returns executive file path for the specified process
std::string GetExePath(DWORD dwProcID)
{
	HANDLE hSnap = CreateToolhelp32Snapshot(TH32CS_SNAPMODULE,dwProcID);
	MODULEENTRY32 me;
	std::string path;
	me.dwSize=sizeof(me);

	if (Module32First(hSnap,&me))
		path = me.szExePath;

	CloseHandle(hSnap);
	return path;
}

Nie pytajcie skąd to mam, bo nie pamiętam i nie chce mi się szukać.
Czy działa zawsze - to raczej wątpliwe.
Oczywiście Win32 API.

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)