{"id":34219,"date":"2025-11-13T04:31:27","date_gmt":"2025-11-13T01:31:27","guid":{"rendered":"https:\/\/fatihsoysal.com\/blog\/go-ile-konsol-tabanli-metin-goruntuleyici-nasil-yapilir\/"},"modified":"2025-11-13T04:31:27","modified_gmt":"2025-11-13T01:31:27","slug":"go-ile-konsol-tabanli-metin-goruntuleyici-nasil-yapilir","status":"publish","type":"post","link":"https:\/\/fatihsoysal.com\/blog\/go-ile-konsol-tabanli-metin-goruntuleyici-nasil-yapilir\/","title":{"rendered":"Go ile Konsol Tabanl\u0131 Metin G\u00f6r\u00fcnt\u00fcleyici Nas\u0131l Yap\u0131l\u0131r?"},"content":{"rendered":"<p><body><\/p>\n<p>\n    Go programlama dili kullanarak kendi konsol tabanl\u0131 metin g\u00f6r\u00fcnt\u00fcleyicinizi geli\u015ftirmek ister misiniz? Bu detayl\u0131 rehberde, s\u0131f\u0131rdan ba\u015flayarak g\u00fc\u00e7l\u00fc ve verimli bir metin g\u00f6r\u00fcnt\u00fcleyici olu\u015fturman\u0131n ad\u0131mlar\u0131n\u0131 ke\u015ffedecek, b\u00fcy\u00fck dosyalar\u0131 kolayca incelemenizi sa\u011flayacak teknikleri ve ipu\u00e7lar\u0131n\u0131 \u00f6\u011freneceksiniz. Modern geli\u015ftirme ortamlar\u0131nda s\u0131kl\u0131kla kar\u015f\u0131la\u015f\u0131lan bu ihtiyaca y\u00f6nelik pratik \u00e7\u00f6z\u00fcmlerle, Go&#8217;nun performans\u0131n\u0131 ve sadeli\u011fini bir araya getiren bir ara\u00e7 in\u015fa edece\u011fiz.\n<\/p>\n<p>\n    G\u00fcn\u00fcm\u00fcz\u00fcn karma\u015f\u0131k yaz\u0131l\u0131m geli\u015ftirme d\u00fcnyas\u0131nda, terminal tabanl\u0131 ara\u00e7lar, h\u0131zlar\u0131 ve kaynak verimlilikleri sayesinde hala vazge\u00e7ilmez bir yere sahiptir. \u00d6zellikle sunucu ortamlar\u0131nda, SSH \u00fczerinden ba\u011flan\u0131lan uzak sistemlerde veya GUI (Grafik Kullan\u0131c\u0131 Aray\u00fcz\u00fc) bulunmayan minimal i\u015fletim sistemlerinde, metin dosyalar\u0131n\u0131 incelemek i\u00e7in konsol tabanl\u0131 bir g\u00f6r\u00fcnt\u00fcleyiciye ihtiya\u00e7 duyar\u0131z. Varsay\u0131lan olarak sistemlerde bulunan <code>less<\/code> veya <code>cat<\/code> gibi ara\u00e7lar temel ihtiya\u00e7lar\u0131 kar\u015f\u0131lasa da, bazen daha geli\u015fmi\u015f \u00f6zelliklere (\u00f6rne\u011fin, renklendirme, geli\u015fmi\u015f arama, \u00f6zel gezinme) sahip \u00f6zelle\u015ftirilebilir bir \u00e7\u00f6z\u00fcme ihtiya\u00e7 duyulur. \u0130\u015fte tam da bu noktada, Go ile kendi metin g\u00f6r\u00fcnt\u00fcleyicimizi geli\u015ftirmek, bize hem esneklik hem de \u00fcst\u00fcn performans sunar.\n<\/p>\n<p>\n    Dahas\u0131, Go dili, derlenmi\u015f ve ba\u011f\u0131ms\u0131z \u00e7al\u0131\u015fabilen ikili dosyalar \u00fcretme yetene\u011fi sayesinde, olu\u015fturdu\u011fumuz uygulaman\u0131n farkl\u0131 platformlarda (Windows, Linux, macOS) sorunsuz bir \u015fekilde \u00e7al\u0131\u015fmas\u0131n\u0131 sa\u011flar. Bu, geli\u015ftiriciler i\u00e7in da\u011f\u0131t\u0131m\u0131 ve bak\u0131m\u0131 olduk\u00e7a kolayla\u015ft\u0131ran \u00f6nemli bir avantajd\u0131r. \u00d6rne\u011fin, b\u00fcy\u00fck log dosyalar\u0131n\u0131 analiz etmek, yap\u0131land\u0131rma dosyalar\u0131n\u0131 h\u0131zl\u0131ca g\u00f6zden ge\u00e7irmek veya uzun kod dosyalar\u0131nda gezinmek gibi senaryolarda, GUI tabanl\u0131 bir edit\u00f6r\u00fcn a\u00e7\u0131l\u0131\u015f s\u00fcresini beklemek yerine, konsol tabanl\u0131 bir g\u00f6r\u00fcnt\u00fcleyici \u00e7ok daha h\u0131zl\u0131 ve pratik bir \u00e7\u00f6z\u00fcm sunar. Bir ba\u015fka deyi\u015fle, Go ile yaz\u0131lm\u0131\u015f bir metin g\u00f6r\u00fcnt\u00fcleyici, geli\u015ftiricilere zaman kazand\u0131r\u0131r ve i\u015f ak\u0131\u015flar\u0131n\u0131 h\u0131zland\u0131r\u0131r. Bu t\u00fcr bir arac\u0131n sadece basit bir dosya okuyucu olmaktan \u00f6te, metin i\u015fleme yeteneklerini ve kullan\u0131c\u0131 etkile\u015fimini de i\u00e7eren g\u00fc\u00e7l\u00fc bir yard\u0131mc\u0131ya d\u00f6n\u00fc\u015fmesi m\u00fcmk\u00fcnd\u00fcr.\n<\/p>\n<p>\n    Peki, bu arac\u0131 in\u015fa ederken hangi Go k\u00fct\u00fcphanelerini kullanaca\u011f\u0131z? Terminal tabanl\u0131 uygulamalar geli\u015ftirmek i\u00e7in Go ekosisteminde birka\u00e7 pop\u00fcler k\u00fct\u00fcphane bulunmaktad\u0131r. Bunlar aras\u0131nda <code>termbox-go<\/code> ve <code>tcell<\/code> \u00f6ne \u00e7\u0131kar. Her iki k\u00fct\u00fcphane de d\u00fc\u015f\u00fck seviyeli terminal giri\u015f\/\u00e7\u0131k\u0131\u015f i\u015flemlerini soyutlayarak bize karakter tabanl\u0131 kullan\u0131c\u0131 aray\u00fczleri olu\u015fturma imkan\u0131 sunar. Bu makalede, daha modern ve aktif olarak geli\u015ftirilen <code>tcell<\/code> k\u00fct\u00fcphanesini tercih ederek, imle\u00e7 hareketlerinden klavye olaylar\u0131na kadar bir\u00e7ok detay\u0131 nas\u0131l y\u00f6netece\u011fimizi ad\u0131m ad\u0131m inceleyece\u011fiz. Sonu\u00e7 olarak, bu s\u00fcre\u00e7 sadece bir metin g\u00f6r\u00fcnt\u00fcleyici in\u015fa etmekle kalmayacak, ayn\u0131 zamanda Go ile interaktif terminal uygulamalar\u0131 geli\u015ftirme konusunda sa\u011flam bir temel olu\u015fturman\u0131za yard\u0131mc\u0131 olacakt\u0131r. Bu da \u015f\u00fcphesiz, genel Go geli\u015ftirme yeteneklerinizi bir \u00fcst seviyeye ta\u015f\u0131yacakt\u0131r.\n<\/p>\n<h2>Go ile Terminal Uygulamalar\u0131 Geli\u015ftirmenin Temelleri: Tcell K\u00fct\u00fcphanesi<\/h2>\n<p>\n    Go ile konsol tabanl\u0131 uygulamalar geli\u015ftirmenin anahtar\u0131, terminalin d\u00fc\u015f\u00fck seviyeli \u00f6zelliklerini soyutlayan k\u00fct\u00fcphaneleri kullanmaktan ge\u00e7er. Bu ba\u011flamda, <code>tcell<\/code> k\u00fct\u00fcphanesi, zengin \u00f6zellikleri ve aktif deste\u011fi ile \u00f6ne \u00e7\u0131kan g\u00fc\u00e7l\u00fc bir ara\u00e7t\u0131r. <code>tcell<\/code>, terminalin ekran\u0131n\u0131 y\u00f6netmek, karakterleri belirli konumlara yazd\u0131rmak, renkleri ayarlamak ve klavye\/fare olaylar\u0131n\u0131 dinlemek i\u00e7in gerekli t\u00fcm fonksiyonlar\u0131 sa\u011flar. Bu k\u00fct\u00fcphane sayesinde, do\u011frudan ANSI ka\u00e7\u0131\u015f kodlar\u0131yla u\u011fra\u015fmak yerine, daha y\u00fcksek seviyeli ve anla\u015f\u0131l\u0131r bir API ile etkile\u015fimli uygulamalar geli\u015ftirebiliriz.\n<\/p>\n<p>\n    \u00d6ncelikle, <code>tcell<\/code> k\u00fct\u00fcphanesini projenize dahil etmeniz gerekir. Bunu terminalinizde a\u015fa\u011f\u0131daki komutla yapabilirsiniz:\n<\/p>\n<pre><code>\ngo get github.com\/gdamore\/tcell\/v2\n<\/pre>\n<p><\/code><\/p>\n<p>\n    K\u00fct\u00fcphaneyi ba\u015far\u0131yla indirdikten sonra, basit bir \"Merhaba D\u00fcnya\" \u00f6rne\u011fi ile <code>tcell<\/code> ekran\u0131n\u0131 nas\u0131l ba\u015flataca\u011f\u0131m\u0131z\u0131 ve temel metin \u00e7\u0131kt\u0131s\u0131 alaca\u011f\u0131m\u0131z\u0131 g\u00f6relim. Bu ba\u015flang\u0131\u00e7, her etkile\u015fimli terminal uygulamas\u0131n\u0131n temelini olu\u015fturur.\n<\/p>\n<pre><code>\npackage main\n\nimport (\n\t\"fmt\"\n\t\"log\"\n\t\"os\"\n\n\t\"github.com\/gdamore\/tcell\/v2\"\n)\n\nfunc main() {\n\t\/\/ tcell ekran\u0131n\u0131 ba\u015flat\n\tscreen, err := tcell.NewScreen()\n\tif err != nil {\n\t\tlog.Fatalf(\"%+v\", err)\n\t}\n\tif err = screen.Init(); err != nil {\n\t\tlog.Fatalf(\"%+v\", err)\n\t}\n\n\t\/\/ Varsay\u0131lan stili ayarla\n\tdefStyle := tcell.StyleDefault.Background(tcell.ColorBlack).Foreground(tcell.ColorWhite)\n\tscreen.SetStyle(defStyle)\n\tscreen.Clear()\n\n\t\/\/ Ekrana metin yazma fonksiyonu\n\tputText := func(x, y int, style tcell.Style, text string) {\n\t\tfor i, r := range text {\n\t\t\tscreen.SetContent(x+i, y, r, nil, style)\n\t\t}\n\t}\n\n\tputText(1, 1, defStyle, \"Go ile Metin G\u00f6r\u00fcnt\u00fcleyici!\")\n\tputText(1, 2, defStyle, \"\u00c7\u0131kmak i\u00e7in 'ESC' tu\u015funa bas\u0131n.\")\n\tscreen.Show()\n\n\t\/\/ Klavye olaylar\u0131n\u0131 dinle\n\tfor {\n\t\tev := screen.PollEvent()\n\t\tswitch ev := ev.(type) {\n\t\tcase *tcell.EventKey:\n\t\t\tif ev.Key() == tcell.KeyEscape {\n\t\t\t\tscreen.Fini() \/\/ Ekran\u0131 temizle ve terminali eski haline getir\n\t\t\t\tos.Exit(0)\n\t\t\t}\n\t\t}\n\t}\n}\n<\/pre>\n<p><\/code><\/p>\n<p>\n    Yukar\u0131daki kod blo\u011fu, <code>tcell<\/code> ile basit bir ekran olu\u015fturma ve metin yazd\u0131rma i\u015flemini g\u00f6stermektedir. <code>screen.Init()<\/code> \u00e7a\u011fr\u0131s\u0131 terminali \"raw\" moda ge\u00e7irir ve <code>screen.Fini()<\/code> ise terminali normal durumuna d\u00f6nd\u00fcr\u00fcr. Bu, kullan\u0131c\u0131 deneyimi a\u00e7\u0131s\u0131ndan kritik bir ad\u0131md\u0131r, \u00e7\u00fcnk\u00fc uygulaman\u0131z\u0131n terminali d\u00fczg\u00fcn bir \u015fekilde devralmas\u0131n\u0131 ve serbest b\u0131rakmas\u0131n\u0131 sa\u011flar. <code>screen.SetContent(x, y, r, nil, style)<\/code> fonksiyonu belirli bir (x, y) koordinat\u0131na bir karakter (<code>r<\/code>) yazar ve stilini belirler. Ayr\u0131ca, <code>screen.PollEvent()<\/code> ile klavye olaylar\u0131n\u0131 dinleyerek uygulaman\u0131n kullan\u0131c\u0131dan gelen girdilere tepki vermesini sa\u011flayabiliriz. Bu, metin g\u00f6r\u00fcnt\u00fcleyicimizin temel navigasyon ve kontrol mekanizmalar\u0131n\u0131 olu\u015fturmak i\u00e7in elzemdir.\n<\/p>\n<aside class=\"expert-tip\">\n    Uzman \u0130pucu: <code>tcell<\/code> ile geli\u015ftirme yaparken, \u00f6zellikle performans a\u00e7\u0131s\u0131ndan, ekran g\u00fcncellemelerini minimize etmek \u00f6nemlidir. Ekran\u0131 tamamen temizleyip yeniden \u00e7izmek yerine, sadece de\u011fi\u015fen b\u00f6lgeleri g\u00fcncellemek veya bir \"kirli\" b\u00f6lge (dirty region) mekanizmas\u0131 kullanmak daha verimli olacakt\u0131r. B\u00fcy\u00fck metin dosyalar\u0131 i\u015flerken bu teknik, uygulaman\u0131z\u0131n daha ak\u0131c\u0131 \u00e7al\u0131\u015fmas\u0131n\u0131 sa\u011flar. Bu sayede, gereksiz yeniden \u00e7izimlerden ka\u00e7\u0131n\u0131larak CPU ve GPU d\u00f6ng\u00fclerinden tasarruf edilir.<br \/>\n<\/aside>\n<p>\n    Ekran\u0131n boyutunu \u00f6\u011frenmek i\u00e7in <code>screen.Size()<\/code> fonksiyonunu kullanabiliriz. Bu bilgi, metni ekrana s\u0131\u011fd\u0131rmak, kayd\u0131rma \u00e7ubuklar\u0131n\u0131 konumland\u0131rmak ve genel d\u00fczeni dinamik olarak ayarlamak i\u00e7in hayati \u00f6neme sahiptir. Ayr\u0131ca, <code>tcell<\/code> farkl\u0131 terminal t\u00fcrlerini ve renk \u00f6zelliklerini otomatik olarak alg\u0131lar, bu da \u00e7apraz platform uyumlulu\u011funu kolayla\u015ft\u0131r\u0131r. K\u00fct\u00fcphanenin sundu\u011fu bu otomasyon, geli\u015ftiricilerin farkl\u0131 ortamlarda test yapma y\u00fck\u00fcn\u00fc azalt\u0131r ve daha geni\u015f bir kullan\u0131c\u0131 kitlesine ula\u015fmalar\u0131n\u0131 sa\u011flar. Sonu\u00e7 olarak, <code>tcell<\/code>, Go ile g\u00fc\u00e7l\u00fc ve kullan\u0131c\u0131 dostu terminal uygulamalar\u0131 olu\u015fturmak i\u00e7in gereken sa\u011flam bir temel sunar.\n<\/p>\n<h2>Basit Bir Metin G\u00f6r\u00fcnt\u00fcleyicinin \u00c7ekirde\u011fi Nas\u0131l Olu\u015fturulur?<\/h2>\n<p>\n    Basit bir metin g\u00f6r\u00fcnt\u00fcleyicinin kalbi, \u00f6ncelikle dosya okuma ve bu i\u00e7eri\u011fi ekranda g\u00f6sterim yetene\u011finde yatar. Go'da dosya i\u015flemleri olduk\u00e7a sezgisel ve g\u00fc\u00e7l\u00fcd\u00fcr. Bir metin dosyas\u0131n\u0131 okuyup sat\u0131r sat\u0131r i\u015flemek, g\u00f6r\u00fcnt\u00fcleyicimizin temelini olu\u015fturur. Bu b\u00f6l\u00fcmde, bir dosyay\u0131 nas\u0131l a\u00e7\u0131p okuyaca\u011f\u0131m\u0131z\u0131, i\u00e7eri\u011fini bellekte nas\u0131l tutaca\u011f\u0131m\u0131z\u0131 ve <code>tcell<\/code> kullanarak ekrana nas\u0131l yazd\u0131raca\u011f\u0131m\u0131z\u0131 ad\u0131m ad\u0131m inceleyece\u011fiz.\n<\/p>\n<p>\n    \u00d6ncelikle, Go'nun standart k\u00fct\u00fcphanesi <code>os<\/code> ve <code>bufio<\/code> paketlerini kullanarak bir dosyay\u0131 okumam\u0131z gerekecek. <code>bufio.Scanner<\/code>, \u00f6zellikle sat\u0131r baz\u0131nda okuma i\u00e7in \u00e7ok verimli bir y\u00f6ntem sunar. Dosyan\u0131n tamam\u0131n\u0131 belle\u011fe y\u00fcklemek, \u00f6zellikle b\u00fcy\u00fck dosyalar s\u00f6z konusu oldu\u011funda performans sorunlar\u0131na yol a\u00e7abilir. Bu nedenle, dosyan\u0131n i\u00e7eri\u011fini bir dilim (slice) i\u00e7inde sat\u0131rlar halinde saklamak daha uygun bir yakla\u015f\u0131md\u0131r.\n<\/p>\n<pre><code>\npackage main\n\nimport (\n\t\"bufio\"\n\t\"fmt\"\n\t\"log\"\n\t\"os\"\n\t\"strconv\"\n\n\t\"github.com\/gdamore\/tcell\/v2\"\n)\n\n\/\/ ViewerState, g\u00f6r\u00fcnt\u00fcleyicinin anl\u0131k durumunu tutar\ntype ViewerState struct {\n\tlines        []string \/\/ Dosyadaki t\u00fcm sat\u0131rlar\n\toffsetY      int      \/\/ Ekran\u0131n \u00fcst k\u0131sm\u0131ndaki ilk sat\u0131r\u0131n indeksi (kayd\u0131rma i\u00e7in)\n\toffsetX      int      \/\/ Ekran\u0131n sol k\u0131sm\u0131ndaki ilk karakterin indeksi (yatay kayd\u0131rma)\n\twidth, height int      \/\/ Terminalin geni\u015fli\u011fi ve y\u00fcksekli\u011fi\n\tscreen       tcell.Screen\n\tfileName     string\n}\n\n\/\/ Yeni bir ViewerState olu\u015fturur\nfunc NewViewerState(screen tcell.Screen, fileName string) *ViewerState {\n\treturn &ViewerState{\n\t\tscreen:   screen,\n\t\tfileName: fileName,\n\t\tlines:    []string{},\n\t\toffsetY:  0,\n\t\toffsetX:  0,\n\t}\n}\n\n\/\/ Dosyay\u0131 okur ve sat\u0131rlar\u0131 belle\u011fe y\u00fckler\nfunc (vs *ViewerState) LoadFile() error {\n\tfile, err := os.Open(vs.fileName)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"dosya a\u00e7\u0131lamad\u0131: %w\", err)\n\t}\n\tdefer file.Close()\n\n\tscanner := bufio.NewScanner(file)\n\tfor scanner.Scan() {\n\t\tvs.lines = append(vs.lines, scanner.Text())\n\t}\n\n\tif err := scanner.Err(); err != nil {\n\t\treturn fmt.Errorf(\"dosya okunurken hata: %w\", err)\n\t}\n\treturn nil\n}\n\n\/\/ Ekran\u0131 temizler ve metni \u00e7izer\nfunc (vs *ViewerState) Draw() {\n\tvs.screen.Clear()\n\tvs.width, vs.height = vs.screen.Size()\n\n\tdefStyle := tcell.StyleDefault.Background(tcell.ColorBlack).Foreground(tcell.ColorWhite)\n\tlineNumStyle := tcell.StyleDefault.Background(tcell.ColorBlack).Foreground(tcell.ColorDarkCyan)\n\t\n\t\/\/ Sat\u0131r numaralar\u0131 i\u00e7in ay\u0131rd\u0131\u011f\u0131m\u0131z geni\u015flik\n\tlineNumWidth := 5 \n\n\tfor y := 0; y < vs.height; y++ {\n\t\tlineIdx := vs.offsetY + y\n\t\tif lineIdx >= len(vs.lines) {\n\t\t\tbreak \/\/ Dosyan\u0131n sonuna ula\u015f\u0131ld\u0131\n\t\t}\n\n\t\t\/\/ Sat\u0131r numaras\u0131 \u00e7izimi\n\t\tlineNumStr := fmt.Sprintf(\"%4d \", lineIdx+1) \/\/ 4 karakter geni\u015fli\u011finde sa\u011fa hizal\u0131\n\t\tvs.putText(0, y, lineNumStyle, lineNumStr)\n\n\t\t\/\/ Metin \u00e7izimi\n\t\tline := vs.lines[lineIdx]\n\t\tif vs.offsetX < len(line) {\n\t\t\t\/\/ Sadece ekrana s\u0131\u011fan k\u0131sm\u0131 g\u00f6ster\n\t\t\tdisplayLine := line[vs.offsetX:]\n\t\t\tif len(displayLine) > vs.width-lineNumWidth { \/\/ Ekran geni\u015fli\u011finden sat\u0131r numaras\u0131 geni\u015fli\u011fini \u00e7\u0131kar\n\t\t\t\tdisplayLine = displayLine[:vs.width-lineNumWidth]\n\t\t\t}\n\t\t\tvs.putText(lineNumWidth, y, defStyle, displayLine)\n\t\t} else {\n\t\t\t\/\/ Yatay kayd\u0131rma \u00e7ok fazlaysa bo\u015f b\u0131rak\n\t\t\tvs.putText(lineNumWidth, y, defStyle, \"\")\n\t\t}\n\t}\n\tvs.screen.Show()\n}\n\n\/\/ Yard\u0131mc\u0131 fonksiyon: Belirtilen koordinatlara metin yazar\nfunc (vs *ViewerState) putText(x, y int, style tcell.Style, text string) {\n\tfor i, r := range text {\n\t\tvs.screen.SetContent(x+i, y, r, nil, style)\n\t}\n}\n\nfunc main() {\n\tif len(os.Args) < 2 {\n\t\tfmt.Println(\"Kullan\u0131m: go run main.go <dosya_ad\u0131>\")\n\t\tos.Exit(1)\n\t}\n\tfileName := os.Args[1]\n\n\tscreen, err := tcell.NewScreen()\n\tif err != nil {\n\t\tlog.Fatalf(\"%+v\", err)\n\t}\n\tif err = screen.Init(); err != nil {\n\t\tlog.Fatalf(\"%+v\", err)\n\t}\n\tdefer screen.Fini()\n\n\tvs := NewViewerState(screen, fileName)\n\tif err := vs.LoadFile(); err != nil {\n\t\tlog.Fatalf(\"%+v\", err)\n\t}\n\n\tvs.Draw() \/\/ \u0130lk \u00e7izimi yap\n\n\t\/\/ Klavye olay d\u00f6ng\u00fcs\u00fc burada ba\u015flayacak\n\t\/\/ Bu k\u0131s\u0131m bir sonraki b\u00f6l\u00fcmde daha detayl\u0131 ele al\u0131nacak\n\tfor {\n\t\tev := screen.PollEvent()\n\t\tswitch ev := ev.(type) {\n\t\tcase *tcell.EventKey:\n\t\t\tif ev.Key() == tcell.KeyEscape {\n\t\t\t\treturn \/\/ main'den \u00e7\u0131k\u0131\u015f\n\t\t\t}\n\t\t\t\/\/ Di\u011fer tu\u015f olaylar\u0131 (yukar\u0131, a\u015fa\u011f\u0131, sayfa vb.) burada i\u015flenecek\n\t\tcase *tcell.EventResize:\n\t\t\tvs.Draw() \/\/ Ekran boyutu de\u011fi\u015fti\u011finde yeniden \u00e7iz\n\t\t}\n\t}\n}\n<\/pre>\n<p><\/code><\/p>\n<p>\n    Bu kodda <code>ViewerState<\/code> yap\u0131s\u0131, g\u00f6r\u00fcnt\u00fclenecek metin sat\u0131rlar\u0131n\u0131 (<code>lines<\/code>), kayd\u0131rma konumunu (<code>offsetY<\/code>, <code>offsetX<\/code>) ve ekran referans\u0131n\u0131 bar\u0131nd\u0131r\u0131r. <code>LoadFile()<\/code> metodu, belirtilen dosyay\u0131 a\u00e7ar ve her sat\u0131r\u0131 <code>lines<\/code> dilimine ekler. Bu yakla\u015f\u0131m, t\u00fcm dosyan\u0131n tek bir dize olarak okunmas\u0131ndan \u00e7ok daha esnektir ve sat\u0131r baz\u0131nda i\u015flem yapma yetene\u011fi sunar. <code>Draw()<\/code> metodu ise ekran\u0131 temizler, terminalin mevcut boyutlar\u0131n\u0131 al\u0131r ve <code>offsetY<\/code> ve <code>offsetX<\/code> de\u011ferlerini kullanarak do\u011fru metin par\u00e7alar\u0131n\u0131 ekrana yazd\u0131r\u0131r. Sat\u0131r numaralar\u0131n\u0131 da ekranda g\u00f6stererek kullan\u0131c\u0131ya daha fazla ba\u011flam sa\u011fl\u0131yoruz.\n<\/p>\n<p>\n    \u00d6nemli bir detay da, <code>Draw()<\/code> metodunun her \u00e7a\u011fr\u0131ld\u0131\u011f\u0131nda terminalin geni\u015fli\u011fi ve y\u00fcksekli\u011finin tekrar al\u0131nmas\u0131d\u0131r. Bu, kullan\u0131c\u0131n\u0131n terminal penceresini yeniden boyutland\u0131rmas\u0131 durumunda g\u00f6r\u00fcnt\u00fcleyicinin dinamik olarak adapte olmas\u0131n\u0131 sa\u011flar. Ayr\u0131ca, metin yatay olarak da kayd\u0131r\u0131labilir. Bu sayede uzun sat\u0131rlar bile tamamen g\u00f6r\u00fcnt\u00fclenebilir. G\u00f6r\u00fcnt\u00fcleyicimizin bu temel yap\u0131s\u0131 \u00fczerine, sonraki b\u00f6l\u00fcmde kullan\u0131c\u0131 etkile\u015fimini, yani kayd\u0131rma ve di\u011fer klavye olaylar\u0131n\u0131 nas\u0131l y\u00f6netece\u011fimizi in\u015fa edece\u011fiz. Bu ad\u0131mlar, bir metin g\u00f6r\u00fcnt\u00fcleyicinin sadece statik bir \u00e7\u0131kt\u0131 arac\u0131 olmaktan \u00e7\u0131k\u0131p, ger\u00e7ek anlamda interaktif bir uygulamaya d\u00f6n\u00fc\u015fmesini sa\u011flayacakt\u0131r.\n<\/p>\n<h2>Kullan\u0131c\u0131 Etkile\u015fimi ve \u0130mle\u00e7 Y\u00f6netimi Nas\u0131l Sa\u011flan\u0131r?<\/h2>\n<p>\n    Bir metin g\u00f6r\u00fcnt\u00fcleyicinin interaktif olabilmesi i\u00e7in kullan\u0131c\u0131dan gelen klavye girdilerine tepki vermesi gerekir. Bu b\u00f6l\u00fcm, <code>tcell<\/code> k\u00fct\u00fcphanesini kullanarak yukar\u0131\/a\u015fa\u011f\u0131 kayd\u0131rma, sayfa atlama ve yatay kayd\u0131rma gibi temel navigasyon \u00f6zelliklerini nas\u0131l ekleyece\u011fimizi detayland\u0131racakt\u0131r. \u0130mle\u00e7 y\u00f6netimi derken, asl\u0131nda g\u00f6r\u00fcnt\u00fcleyicinin hangi b\u00f6l\u00fcm\u00fcn\u00fcn ekranda oldu\u011funu belirleyen kayd\u0131rma konumunu kastediyoruz.\n<\/p>\n<p>\n    <code>tcell.Screen.PollEvent()<\/code> fonksiyonu, kullan\u0131c\u0131n\u0131n yapt\u0131\u011f\u0131 klavye bas\u0131mlar\u0131n\u0131 veya di\u011fer terminal olaylar\u0131n\u0131 (\u00f6rne\u011fin pencere boyutu de\u011fi\u015fimi) bir olay nesnesi olarak d\u00f6nd\u00fcr\u00fcr. Bizim yapmam\u0131z gereken, bu olay nesnesini kontrol edip uygun aksiyonlar\u0131 tetiklemektir. En temel ihtiya\u00e7, metni dikey olarak kayd\u0131rmakt\u0131r. Bu, <code>offsetY<\/code> de\u011fi\u015fkenini art\u0131rarak (a\u015fa\u011f\u0131 kayd\u0131rma) veya azaltarak (yukar\u0131 kayd\u0131rma) yap\u0131l\u0131r. Benzer \u015fekilde, yatay kayd\u0131rma i\u00e7in <code>offsetX<\/code> de\u011fi\u015fkeni kullan\u0131l\u0131r.\n<\/p>\n<pre><code>\npackage main\n\nimport (\n\t\"bufio\"\n\t\"fmt\"\n\t\"log\"\n\t\"os\"\n\t\"strconv\" \/\/ strconv'\u0131 ekledik\n\n\t\"github.com\/gdamore\/tcell\/v2\"\n)\n\n\/\/ ViewerState yap\u0131s\u0131 (\u00f6nceki b\u00f6l\u00fcmden kopyaland\u0131)\ntype ViewerState struct {\n\tlines        []string\n\toffsetY      int\n\toffsetX      int\n\twidth, height int\n\tscreen       tcell.Screen\n\tfileName     string\n}\n\n\/\/ NewViewerState fonksiyonu (\u00f6nceki b\u00f6l\u00fcmden kopyaland\u0131)\nfunc NewViewerState(screen tcell.Screen, fileName string) *ViewerState {\n\treturn &ViewerState{\n\t\tscreen:   screen,\n\t\tfileName: fileName,\n\t\tlines:    []string{},\n\t\toffsetY:  0,\n\t\toffsetX:  0,\n\t}\n}\n\n\/\/ LoadFile metodu (\u00f6nceki b\u00f6l\u00fcmden kopyaland\u0131)\nfunc (vs *ViewerState) LoadFile() error {\n\tfile, err := os.Open(vs.fileName)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"dosya a\u00e7\u0131lamad\u0131: %w\", err)\n\t}\n\tdefer file.Close()\n\n\tscanner := bufio.NewScanner(file)\n\tfor scanner.Scan() {\n\t\tvs.lines = append(vs.lines, scanner.Text())\n\t}\n\n\tif err := scanner.Err(); err != nil {\n\t\treturn fmt.Errorf(\"dosya okunurken hata: %w\", err)\n\t}\n\treturn nil\n}\n\n\/\/ Draw metodu (\u00f6nceki b\u00f6l\u00fcmden kopyaland\u0131, sat\u0131r numaras\u0131 geni\u015fli\u011fi i\u00e7in lineNumWidth eklendi)\nfunc (vs *ViewerState) Draw() {\n\tvs.screen.Clear()\n\tvs.width, vs.height = vs.screen.Size()\n\n\tdefStyle := tcell.StyleDefault.Background(tcell.ColorBlack).Foreground(tcell.ColorWhite)\n\tlineNumStyle := tcell.StyleDefault.Background(tcell.ColorBlack).Foreground(tcell.ColorDarkCyan)\n\t\n\tlineNumWidth := 5 \/\/ Sat\u0131r numaralar\u0131 i\u00e7in ay\u0131rd\u0131\u011f\u0131m\u0131z geni\u015flik\n\n\t\/\/ Header\/Status bar\n\theaderStyle := tcell.StyleDefault.Background(tcell.ColorDarkBlue).Foreground(tcell.ColorWhite)\n\tstatusText := fmt.Sprintf(\"Dosya: %s - Sat\u0131r: %d\/%d - S\u00fctun: %d\", vs.fileName, vs.offsetY+1, len(vs.lines), vs.offsetX+1)\n\tvs.putText(0, 0, headerStyle, statusText + fmt.Sprintf(\"%*s\", vs.width - len(statusText), \"\")) \/\/ Ekran\u0131 doldur\n\n\t\/\/ Metin \u00e7izimi (y=0 art\u0131k header i\u00e7in kullan\u0131ld\u0131\u011f\u0131 i\u00e7in y=1'den ba\u015fl\u0131yoruz)\n\tfor y := 1; y < vs.height; y++ { \/\/ Ekran\u0131n ilk sat\u0131r\u0131 ba\u015fl\u0131k i\u00e7in ayr\u0131ld\u0131\n\t\tlineIdx := vs.offsetY + (y - 1) \/\/ Metin sat\u0131r indeksini hesapla\n\t\tif lineIdx >= len(vs.lines) {\n\t\t\tbreak\n\t\t}\n\n\t\t\/\/ Sat\u0131r numaras\u0131 \u00e7izimi\n\t\tlineNumStr := fmt.Sprintf(\"%4d \", lineIdx+1) \/\/ 4 karakter geni\u015fli\u011finde sa\u011fa hizal\u0131\n\t\tvs.putText(0, y, lineNumStyle, lineNumStr)\n\n\t\tline := vs.lines[lineIdx]\n\t\tif vs.offsetX < len(line) {\n\t\t\tdisplayLine := line[vs.offsetX:]\n\t\t\tmaxLen := vs.width - lineNumWidth \/\/ Ekran geni\u015fli\u011finden sat\u0131r numaras\u0131 geni\u015fli\u011fini \u00e7\u0131kar\n\t\t\tif len(displayLine) > maxLen {\n\t\t\t\tdisplayLine = displayLine[:maxLen]\n\t\t\t}\n\t\t\tvs.putText(lineNumWidth, y, defStyle, displayLine)\n\t\t} else {\n\t\t\tvs.putText(lineNumWidth, y, defStyle, \"\")\n\t\t}\n\t}\n\tvs.screen.Show()\n}\n\n\/\/ putText metodu (\u00f6nceki b\u00f6l\u00fcmden kopyaland\u0131)\nfunc (vs *ViewerState) putText(x, y int, style tcell.Style, text string) {\n\tfor i, r := range text {\n\t\tif x+i >= vs.width { \/\/ Ekran d\u0131\u015f\u0131na ta\u015fan metinleri kes\n\t\t\tbreak\n\t\t}\n\t\tvs.screen.SetContent(x+i, y, r, nil, style)\n\t}\n}\n\n\/\/ main fonksiyonu\nfunc main() {\n\tif len(os.Args) < 2 {\n\t\tfmt.Println(\"Kullan\u0131m: go run main.go <dosya_ad\u0131>\")\n\t\tos.Exit(1)\n\t}\n\tfileName := os.Args[1]\n\n\tscreen, err := tcell.NewScreen()\n\tif err != nil {\n\t\tlog.Fatalf(\"%+v\", err)\n\t}\n\tif err = screen.Init(); err != nil {\n\t\tlog.Fatalf(\"%+v\", err)\n\t}\n\tdefer screen.Fini()\n\n\tvs := NewViewerState(screen, fileName)\n\tif err := vs.LoadFile(); err != nil {\n\t\tlog.Fatalf(\"%+v\", err)\n\t}\n\n\tvs.Draw() \/\/ \u0130lk \u00e7izimi yap\n\n\t\/\/ Klavye olay d\u00f6ng\u00fcs\u00fc\n\tfor {\n\t\tev := screen.PollEvent()\n\t\tswitch ev := ev.(type) {\n\t\tcase *tcell.EventKey:\n\t\t\tswitch ev.Key() {\n\t\t\tcase tcell.KeyEscape, tcell.KeyCtrlC: \/\/ \u00c7\u0131k\u0131\u015f\n\t\t\t\treturn\n\t\t\tcase tcell.KeyUp: \/\/ Yukar\u0131 kayd\u0131r\n\t\t\t\tvs.offsetY = max(0, vs.offsetY-1)\n\t\t\tcase tcell.KeyDown: \/\/ A\u015fa\u011f\u0131 kayd\u0131r\n\t\t\t\tmaxOffset := len(vs.lines) - (vs.height - 1) \/\/ -1 \u00e7\u00fcnk\u00fc ba\u015fl\u0131k sat\u0131r\u0131 var\n\t\t\t\tvs.offsetY = min(max(0, maxOffset), vs.offsetY+1)\n\t\t\tcase tcell.KeyPgUp: \/\/ Sayfa yukar\u0131\n\t\t\t\tvs.offsetY = max(0, vs.offsetY-(vs.height-1))\n\t\t\tcase tcell.KeyPgDn: \/\/ Sayfa a\u015fa\u011f\u0131\n\t\t\t\tmaxOffset := len(vs.lines) - (vs.height - 1)\n\t\t\t\tvs.offsetY = min(max(0, maxOffset), vs.offsetY+(vs.height-1))\n\t\t\tcase tcell.KeyLeft: \/\/ Sola kayd\u0131r\n\t\t\t\tvs.offsetX = max(0, vs.offsetX-1)\n\t\t\tcase tcell.KeyRight: \/\/ Sa\u011fa kayd\u0131r\n\t\t\t\tvs.offsetX = vs.offsetX + 1 \/\/ Sa\u011fda s\u0131n\u0131r yok, sat\u0131r\u0131n sonuna kadar gidebilir\n\t\t\tcase tcell.KeyHome: \/\/ Sat\u0131r ba\u015f\u0131na git\n\t\t\t\tvs.offsetX = 0\n\t\t\tcase tcell.KeyEnd: \/\/ Sat\u0131r sonuna git (basit bir yakla\u015f\u0131m)\n\t\t\t\t\/\/ Her sat\u0131r\u0131n en uzununu bulmak pahal\u0131 olabilir, \u015fimdilik basit tutal\u0131m\n\t\t\t\t\/\/ vs.offsetX = en_uzun_satir_uzunlugu - (vs.width - lineNumWidth)\n\t\t\t\t\/\/ ya da direkt 0 yap\u0131p manuel kayd\u0131rmaya b\u0131rakal\u0131m\n\t\t\t\tvs.offsetX = 0 \/\/ \u015eimdilik, daha geli\u015fmi\u015f bir end i\u015flevi i\u00e7in sat\u0131r uzunlu\u011fu bilgisi gerekir.\n\t\t\t}\n\t\t\tvs.Draw() \/\/ Durum de\u011fi\u015fti\u011finde yeniden \u00e7iz\n\t\tcase *tcell.EventResize:\n\t\t\tvs.Draw() \/\/ Ekran boyutu de\u011fi\u015fti\u011finde yeniden \u00e7iz\n\t\t}\n\t}\n}\n\n\/\/ min fonksiyonu (Go 1.21 \u00f6ncesi i\u00e7in)\nfunc min(a, b int) int {\n\tif a < b {\n\t\treturn a\n\t}\n\treturn b\n}\n\n\/\/ max fonksiyonu (Go 1.21 \u00f6ncesi i\u00e7in)\nfunc max(a, b int) int {\n\tif a > b {\n\t\treturn a\n\t}\n\treturn b\n}\n<\/pre>\n<p><\/code><\/p>\n<p>\n    Yukar\u0131daki kodda, <code>main<\/code> fonksiyonu i\u00e7indeki olay d\u00f6ng\u00fcs\u00fcn\u00fc geni\u015flettik. Art\u0131k <code>tcell.EventKey<\/code> t\u00fcr\u00fcndeki olaylar\u0131 yakal\u0131yor ve \u00e7e\u015fitli tu\u015flara g\u00f6re (yukar\u0131, a\u015fa\u011f\u0131, sayfa yukar\u0131, sayfa a\u015fa\u011f\u0131, sol, sa\u011f, home, end) <code>ViewerState<\/code>'in <code>offsetY<\/code> ve <code>offsetX<\/code> de\u011ferlerini g\u00fcncelliyoruz. Her bir tu\u015f bas\u0131m\u0131ndan sonra <code>vs.Draw()<\/code> metodunu \u00e7a\u011f\u0131rarak ekran\u0131 g\u00fcncelledi\u011fimize dikkat edin. Bu, kullan\u0131c\u0131n\u0131n yapt\u0131\u011f\u0131 her etkile\u015fimden sonra g\u00f6r\u00fcnt\u00fcleyicinin yeni durumu yans\u0131tmas\u0131n\u0131 sa\u011flar.\n<\/p>\n<aside class=\"expert-tip\">\n    Uzman \u0130pucu: Kayd\u0131rma i\u015flemleri s\u0131ras\u0131nda, <code>offsetY<\/code> de\u011ferini s\u0131n\u0131rlamak \u00e7ok \u00f6nemlidir. Negatif bir de\u011fere d\u00fc\u015fmesini veya dosyadaki toplam sat\u0131r say\u0131s\u0131n\u0131 a\u015fmas\u0131n\u0131 engellemelisiniz. Aksi takdirde, uygulama beklenmedik davran\u0131\u015flar sergileyebilir veya hata verebilir. <code>max(0, ...)<\/code> ile negatif de\u011ferleri, <code>min(maxOffset, ...)<\/code> ile de dosya sonunu a\u015fan de\u011ferleri engelliyoruz. Ayr\u0131ca, <code>tcell.EventResize<\/code> olay\u0131n\u0131 ele almak, uygulaman\u0131z\u0131n terminalin yeniden boyutland\u0131r\u0131lmas\u0131na dinamik olarak tepki vermesini sa\u011flar, bu da daha iyi bir kullan\u0131c\u0131 deneyimi sunar.<br \/>\n<\/aside>\n<p>\n    Ayr\u0131ca, kullan\u0131c\u0131ya daha fazla bilgi sunmak amac\u0131yla ekran\u0131n en \u00fcst\u00fcne bir durum \u00e7ubu\u011fu (status bar) ekledik. Bu \u00e7ubuk, dosya ad\u0131n\u0131, mevcut sat\u0131r\/toplam sat\u0131r say\u0131s\u0131n\u0131 ve s\u00fctun konumunu g\u00f6sterir. Bu t\u00fcr bilgilendirme \u00e7ubuklar\u0131, \u00f6zellikle b\u00fcy\u00fck dosyalarla \u00e7al\u0131\u015f\u0131rken kullan\u0131c\u0131n\u0131n dosya i\u00e7indeki konumunu anlamas\u0131na yard\u0131mc\u0131 olur. Yatay kayd\u0131rma i\u00e7in <code>KeyRight<\/code> tu\u015fu <code>offsetX<\/code> de\u011ferini art\u0131r\u0131rken, <code>KeyLeft<\/code> tu\u015fu bu de\u011feri azalt\u0131r. <code>KeyHome<\/code> tu\u015fu <code>offsetX<\/code>'i s\u0131f\u0131rlar, b\u00f6ylece ge\u00e7erli sat\u0131r\u0131n ba\u015f\u0131na d\u00f6ner. <code>KeyEnd<\/code> i\u00e7in ise, her sat\u0131r\u0131n uzunlu\u011fu farkl\u0131 olabilece\u011finden, basit bir yakla\u015f\u0131m olarak yine <code>offsetX<\/code>'i s\u0131f\u0131ra \u00e7ekmeyi tercih ettik. Ger\u00e7ek bir \"end\" i\u015flevi, her sat\u0131r\u0131n maksimum geni\u015fli\u011fini dinamik olarak hesaplamay\u0131 gerektirir ki bu da performans a\u00e7\u0131s\u0131ndan maliyetli olabilir ve daha karma\u015f\u0131k bir yap\u0131y\u0131 gerektirir. Bu ad\u0131mlar, metin g\u00f6r\u00fcnt\u00fcleyicimizi temel bir dosya okuyucudan, ger\u00e7ekten kullan\u0131\u015fl\u0131 ve gezinilebilir bir araca d\u00f6n\u00fc\u015ft\u00fcr\u00fcyor. Bu \u00f6zellikler sayesinde kullan\u0131c\u0131lar, metin dosyalar\u0131 i\u00e7erisinde rahatl\u0131kla hareket edebilecekler.\n<\/p>\n<h2>B\u00fcy\u00fck Dosyalar\u0131 Verimli \u015eekilde G\u00f6r\u00fcnt\u00fcleme Teknikleri Var m\u0131d\u0131r?<\/h2>\n<p>\n    Metin g\u00f6r\u00fcnt\u00fcleyicileri genellikle k\u00fc\u00e7\u00fck ve orta boyutlu dosyalarla sorunsuz \u00e7al\u0131\u015f\u0131rken, gigabaytlarca b\u00fcy\u00fckl\u00fckteki log dosyalar\u0131 veya veri setleriyle kar\u015f\u0131la\u015ft\u0131klar\u0131nda performans sorunlar\u0131 ya\u015famaya ba\u015flarlar. T\u00fcm dosyay\u0131 belle\u011fe y\u00fcklemek, hem bellek t\u00fcketimi hem de uygulama ba\u015flang\u0131\u00e7 s\u00fcresi a\u00e7\u0131s\u0131ndan kabul edilemez olabilir. Bu nedenle, b\u00fcy\u00fck dosyalar\u0131 verimli bir \u015fekilde g\u00f6r\u00fcnt\u00fclemek i\u00e7in \u00f6zel teknikler kullanmak esast\u0131r. En yayg\u0131n ve etkili y\u00f6ntemlerden biri, dosyan\u0131n tamam\u0131n\u0131 de\u011fil, yaln\u0131zca gerekli olan k\u0131s\u0131mlar\u0131n\u0131 belle\u011fe y\u00fcklemektir. Bu yakla\u015f\u0131ma \"lazy loading\" veya \"on-demand loading\" denir.\n<\/p>\n<p>\n    Bir metin dosyas\u0131n\u0131n i\u00e7eri\u011fini sat\u0131r sat\u0131r diskten okumak yerine, b\u00fcy\u00fck bir dosyada gezinirken her sat\u0131r\u0131n disk \u00fczerindeki ba\u015flang\u0131\u00e7 konumunu (offset) ve uzunlu\u011funu \u00f6nceden belirleyebiliriz. Bu, bir t\u00fcr \"sat\u0131r indeksi\" olu\u015fturmak anlam\u0131na gelir. Dosyay\u0131 ilk a\u00e7t\u0131\u011f\u0131m\u0131zda, t\u00fcm dosya i\u00e7eri\u011fini de\u011fil, yaln\u0131zca her sat\u0131r\u0131n ba\u015flad\u0131\u011f\u0131 bayt offsetini ve uzunlu\u011funu bir dilimde saklar\u0131z. B\u00f6ylece, kullan\u0131c\u0131 belirli bir sat\u0131ra atlamak istedi\u011finde, bu indeksi kullanarak do\u011frudan o b\u00f6lgeye seek yapabilir ve sadece o sat\u0131r\u0131 (veya ekran dolusu sat\u0131r\u0131) diskten okuyabiliriz. Bu strateji, bellek kullan\u0131m\u0131n\u0131 minimuma indirirken, h\u0131zl\u0131 eri\u015fim sa\u011flar.\n<\/p>\n<pre><code>\npackage main\n\nimport (\n\t\"bufio\"\n\t\"fmt\"\n\t\"log\"\n\t\"os\"\n\t\"strings\" \/\/ strings paketini ekledik\n\n\t\"github.com\/gdamore\/tcell\/v2\"\n)\n\n\/\/ LineInfo, her sat\u0131r\u0131n dosyadaki ba\u015flang\u0131\u00e7 ve uzunluk bilgilerini tutar\ntype LineInfo struct {\n\tOffset int64 \/\/ Dosya i\u00e7indeki ba\u015flang\u0131\u00e7 bayt offseti\n\tLength int   \/\/ Sat\u0131r\u0131n bayt cinsinden uzunlu\u011fu (yeni sat\u0131r karakteri dahil)\n}\n\n\/\/ ViewerState yap\u0131s\u0131 (g\u00fcncellendi)\ntype ViewerState struct {\n\tlineInfos    []LineInfo \/\/ Her sat\u0131r\u0131n bilgisi\n\tfile         *os.File   \/\/ A\u00e7\u0131k dosya referans\u0131\n\toffsetY      int\n\toffsetX      int\n\twidth, height int\n\tscreen       tcell.Screen\n\tfileName     string\n\ttotalLines   int \/\/ Toplam sat\u0131r say\u0131s\u0131\n}\n\n\/\/ NewViewerState fonksiyonu (g\u00fcncellendi)\nfunc NewViewerState(screen tcell.Screen, fileName string) *ViewerState {\n\treturn &ViewerState{\n\t\tscreen:    screen,\n\t\tfileName:  fileName,\n\t\tlineInfos: []LineInfo{},\n\t\toffsetY:   0,\n\t\toffsetX:   0,\n\t}\n}\n\n\/\/ LoadFile metodu: Sadece sat\u0131r indekslerini belle\u011fe y\u00fckler, t\u00fcm i\u00e7eri\u011fi de\u011fil.\nfunc (vs *ViewerState) LoadFile() error {\n\tfile, err := os.Open(vs.fileName)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"dosya a\u00e7\u0131lamad\u0131: %w\", err)\n\t}\n\tvs.file = file \/\/ Dosya referans\u0131n\u0131 sakla\n\n\tscanner := bufio.NewScanner(file)\n\tcurrentOffset := int64(0)\n\tfor scanner.Scan() {\n\t\tlineBytes := scanner.Bytes()\n\t\t\/\/ Sat\u0131r sonu karakterleri i\u00e7in platforma \u00f6zel durumlar\u0131 y\u00f6netin\n\t\tlineLength := len(lineBytes)\n\t\tif len(lineBytes) > 0 && lineBytes[len(lineBytes)-1] == '\\r' { \/\/ Windows CR LF i\u00e7in\n\t\t\tlineLength++ \/\/ LF'yi de dahil et (e\u011fer varsa)\n\t\t} else { \/\/ Unix\/Linux LF i\u00e7in\n\t\t\tlineLength++ \/\/ LF'yi dahil et\n\t\t}\n\n\t\tvs.lineInfos = append(vs.lineInfos, LineInfo{\n\t\t\tOffset: currentOffset,\n\t\t\tLength: lineLength,\n\t\t})\n\t\tcurrentOffset += int64(lineLength)\n\t}\n\n\tif err := scanner.Err(); err != nil {\n\t\treturn fmt.Errorf(\"dosya okunurken hata: %w\", err)\n\t}\n\tvs.totalLines = len(vs.lineInfos)\n\treturn nil\n}\n\n\/\/ GetLineContent metodu: Belirli bir sat\u0131r\u0131n i\u00e7eri\u011fini diskten okur\nfunc (vs *ViewerState) GetLineContent(lineIdx int) (string, error) {\n\tif lineIdx < 0 || lineIdx >= vs.totalLines {\n\t\treturn \"\", fmt.Errorf(\"ge\u00e7ersiz sat\u0131r indeksi: %d\", lineIdx)\n\t}\n\n\tli := vs.lineInfos[lineIdx]\n\tbuffer := make([]byte, li.Length)\n\n\t\/\/ Dosyan\u0131n ba\u015f\u0131na git ve oku\n\t_, err := vs.file.Seek(li.Offset, io.SeekStart)\n\tif err != nil {\n\t\treturn \"\", fmt.Errorf(\"dosya konumland\u0131rma hatas\u0131: %w\", err)\n\t}\n\t_, err = vs.file.Read(buffer)\n\tif err != nil {\n\t\treturn \"\", fmt.Errorf(\"dosya okuma hatas\u0131: %w\", err)\n\t}\n\t\n\t\/\/ Sat\u0131r sonu karakterini temizle (ekranda g\u00f6r\u00fcnmemesi i\u00e7in)\n\tline := strings.TrimRight(string(buffer), \"\\r\\n\")\n\treturn line, nil\n}\n\n\n\/\/ Draw metodu (g\u00fcncellendi, GetLineContent kullan\u0131yor)\nfunc (vs *ViewerState) Draw() {\n\tvs.screen.Clear()\n\tvs.width, vs.height = vs.screen.Size()\n\n\tdefStyle := tcell.StyleDefault.Background(tcell.ColorBlack).Foreground(tcell.ColorWhite)\n\tlineNumStyle := tcell.StyleDefault.Background(tcell.ColorBlack).Foreground(tcell.ColorDarkCyan)\n\t\n\tlineNumWidth := 5 \n\n\t\/\/ Header\/Status bar\n\theaderStyle := tcell.StyleDefault.Background(tcell.ColorDarkBlue).Foreground(tcell.ColorWhite)\n\tstatusText := fmt.Sprintf(\"Dosya: %s - Sat\u0131r: %d\/%d - S\u00fctun: %d\", vs.fileName, vs.offsetY+1, vs.totalLines, vs.offsetX+1)\n\tvs.putText(0, 0, headerStyle, statusText + fmt.Sprintf(\"%*s\", vs.width - len(statusText), \"\")) \n\n\tfor y := 1; y < vs.height; y++ { \n\t\tlineIdx := vs.offsetY + (y - 1) \n\t\tif lineIdx >= vs.totalLines { \/\/ Toplam sat\u0131r say\u0131s\u0131n\u0131 kullan\n\t\t\tbreak \n\t\t}\n\n\t\tlineContent, err := vs.GetLineContent(lineIdx)\n\t\tif err != nil {\n\t\t\tlineContent = fmt.Sprintf(\"HATA: %v\", err) \/\/ Hata durumunda hata mesaj\u0131 g\u00f6ster\n\t\t}\n\n\t\tlineNumStr := fmt.Sprintf(\"%4d \", lineIdx+1)\n\t\tvs.putText(0, y, lineNumStyle, lineNumStr)\n\n\t\tif vs.offsetX < len(lineContent) {\n\t\t\tdisplayLine := lineContent[vs.offsetX:]\n\t\t\tmaxLen := vs.width - lineNumWidth\n\t\t\tif len(displayLine) > maxLen {\n\t\t\t\tdisplayLine = displayLine[:maxLen]\n\t\t\t}\n\t\t\tvs.putText(lineNumWidth, y, defStyle, displayLine)\n\t\t} else {\n\t\t\tvs.putText(lineNumWidth, y, defStyle, \"\")\n\t\t}\n\t}\n\tvs.screen.Show()\n}\n\n\/\/ putText, min, max fonksiyonlar\u0131 ayn\u0131 kal\u0131r (\u00f6nceki b\u00f6l\u00fcmden kopyaland\u0131)\n\n\/\/ main fonksiyonu (defer vs.file.Close() eklenerek g\u00fcncellendi)\nfunc main() {\n\tif len(os.Args) < 2 {\n\t\tfmt.Println(\"Kullan\u0131m: go run main.go <dosya_ad\u0131>\")\n\t\tos.Exit(1)\n\t}\n\tfileName := os.Args[1]\n\n\tscreen, err := tcell.NewScreen()\n\tif err != nil {\n\t\tlog.Fatalf(\"%+v\", err)\n\t}\n\tif err = screen.Init(); err != nil {\n\t\tlog.Fatalf(\"%+v\", err)\n\t}\n\tdefer screen.Fini() \/\/ screen.Fini() \u00e7a\u011fr\u0131s\u0131 burada kal\u0131r\n\n\tvs := NewViewerState(screen, fileName)\n\tif err := vs.LoadFile(); err != nil {\n\t\tlog.Fatalf(\"%+v\", err)\n\t}\n\tdefer vs.file.Close() \/\/ Dosya referans\u0131n\u0131 kapatmay\u0131 unutma!\n\n\tvs.Draw()\n\n\tfor {\n\t\tev := screen.PollEvent()\n\t\tswitch ev := ev.(type) {\n\t\tcase *tcell.EventKey:\n\t\t\tswitch ev.Key() {\n\t\t\tcase tcell.KeyEscape, tcell.KeyCtrlC:\n\t\t\t\treturn\n\t\t\tcase tcell.KeyUp:\n\t\t\t\tvs.offsetY = max(0, vs.offsetY-1)\n\t\t\tcase tcell.KeyDown:\n\t\t\t\tmaxOffset := vs.totalLines - (vs.height - 1) \/\/ Toplam sat\u0131r say\u0131s\u0131n\u0131 kullan\n\t\t\t\tvs.offsetY = min(max(0, maxOffset), vs.offsetY+1)\n\t\t\tcase tcell.KeyPgUp:\n\t\t\t\tvs.offsetY = max(0, vs.offsetY-(vs.height-1))\n\t\t\tcase tcell.KeyPgDn:\n\t\t\t\tmaxOffset := vs.totalLines - (vs.height - 1)\n\t\t\t\tvs.offsetY = min(max(0, maxOffset), vs.offsetY+(vs.height-1))\n\t\t\tcase tcell.KeyLeft:\n\t\t\t\tvs.offsetX = max(0, vs.offsetX-1)\n\t\t\tcase tcell.KeyRight:\n\t\t\t\tvs.offsetX = vs.offsetX + 1\n\t\t\tcase tcell.KeyHome:\n\t\t\t\tvs.offsetX = 0\n\t\t\tcase tcell.KeyEnd:\n\t\t\t\tvs.offsetX = 0 \n\t\t\t}\n\t\t\tvs.Draw()\n\t\tcase *tcell.EventResize:\n\t\t\tvs.Draw()\n\t\t}\n\t}\n}\n\n\/\/ io paketi import edilmeli\nimport \"io\" \n<\/pre>\n<p><\/code><\/p>\n<p>\n    Bu geli\u015ftirilmi\u015f kodda, <code>ViewerState<\/code> yap\u0131s\u0131na bir <code>[]LineInfo<\/code> dilimi ve a\u00e7\u0131k dosya referans\u0131 (<code>*os.File<\/code>) ekledik. <code>LineInfo<\/code> yap\u0131s\u0131, her sat\u0131r\u0131n dosya i\u00e7indeki ba\u015flang\u0131\u00e7 bayt ofsetini ve uzunlu\u011funu tutar. <code>LoadFile()<\/code> metodu art\u0131k t\u00fcm i\u00e7eri\u011fi belle\u011fe y\u00fcklemek yerine, sadece bu indeks bilgilerini toplar. Bu i\u015flem, dosyan\u0131n boyutundan ba\u011f\u0131ms\u0131z olarak nispeten h\u0131zl\u0131d\u0131r. Kullan\u0131c\u0131 kayd\u0131rma yapt\u0131\u011f\u0131nda veya ekran yeniden \u00e7izildi\u011finde, <code>GetLineContent()<\/code> metodu arac\u0131l\u0131\u011f\u0131yla sadece ekranda g\u00f6r\u00fcnecek olan sat\u0131rlar do\u011frudan diskten okunur. Bu sayede bellek kullan\u0131m\u0131 \u00f6nemli \u00f6l\u00e7\u00fcde azal\u0131r ve uygulama devasa dosyalarla bile ak\u0131c\u0131 bir performans sergiler.\n<\/p>\n<aside class=\"expert-tip\">\n    Uzman \u0130pucu: \u00c7ok b\u00fcy\u00fck dosyalar i\u00e7in (\u00f6rne\u011fin terabaytlarca), sat\u0131r indeksi bile bellekte \u00e7ok yer kaplayabilir. Bu durumda, sadece dosyan\u0131n bir \"penceresinin\" (\u00f6rne\u011fin ilk 100.000 sat\u0131r veya mevcut konum etraf\u0131ndaki belirli say\u0131da sat\u0131r) indeksini bellekte tutmak ve kullan\u0131c\u0131n\u0131n bu pencerenin d\u0131\u015f\u0131na \u00e7\u0131kt\u0131\u011f\u0131nda yeni bir pencere indekslemek gibi daha geli\u015fmi\u015f stratejiler d\u00fc\u015f\u00fcn\u00fclebilir. Bu, \"memory mapping\" gibi daha d\u00fc\u015f\u00fck seviyeli i\u015fletim sistemi \u00f6zelliklerinin kullan\u0131lmas\u0131yla da desteklenebilir. Ancak \u00e7o\u011fu senaryo i\u00e7in mevcut \"lazy loading\" yakla\u015f\u0131m\u0131 yeterli olacakt\u0131r.<br \/>\n<\/aside>\n<p>\n    Ayr\u0131ca, <code>defer vs.file.Close()<\/code> \u00e7a\u011fr\u0131s\u0131n\u0131 <code>main<\/code> fonksiyonuna eklemeyi unutmay\u0131n. Bu, uygulaman\u0131z sona erdi\u011finde a\u00e7\u0131k dosya referans\u0131n\u0131n d\u00fczg\u00fcn bir \u015fekilde kapat\u0131lmas\u0131n\u0131 sa\u011flar ve kaynak s\u0131z\u0131nt\u0131lar\u0131n\u0131 \u00f6nler. Bu optimizasyonlar, metin g\u00f6r\u00fcnt\u00fcleyicimizin sadece i\u015flevsel de\u011fil, ayn\u0131 zamanda performansl\u0131 ve kaynak dostu olmas\u0131n\u0131 garanti eder, bu da onu ger\u00e7ek d\u00fcnya senaryolar\u0131nda \u00e7ok daha kullan\u0131\u015fl\u0131 hale getirir. Bu yakla\u015f\u0131m, Go'nun I\/O performans\u0131ndan en iyi \u015fekilde yararlanarak, b\u00fcy\u00fck metin dosyalar\u0131n\u0131n bile h\u0131zl\u0131 ve etkili bir \u015fekilde y\u00f6netilmesini sa\u011flar.\n<\/p>\n<h2>Vaka Analizi: B\u00fcy\u00fck Bir Log Dosyas\u0131n\u0131 Go Metin G\u00f6r\u00fcnt\u00fcleyici ile \u0130nceleme<\/h2>\n<p>\n    Bir Go metin g\u00f6r\u00fcnt\u00fcleyicisinin ger\u00e7ek d\u00fcnyadaki de\u011ferini anlamak i\u00e7in, pop\u00fcler bir senaryoyu ele alal\u0131m: b\u00fcy\u00fck bir sunucunun sistem log dosyalar\u0131n\u0131 incelemek. Modern sunucular, g\u00fcnl\u00fck terabaytlarca log verisi \u00fcretebilir. Bu log dosyalar\u0131, performans sorunlar\u0131n\u0131 gidermek, g\u00fcvenlik ihlallerini tespit etmek veya uygulaman\u0131n davran\u0131\u015f\u0131n\u0131 izlemek i\u00e7in kritik \u00f6neme sahiptir. Varsay\u0131lan olarak <code>less<\/code> gibi ara\u00e7lar bu t\u00fcr dosyalar\u0131 g\u00f6r\u00fcnt\u00fcleyebilir, ancak kendi Go g\u00f6r\u00fcnt\u00fcleyicimizin sa\u011flad\u0131\u011f\u0131 esneklik ve potansiyel \u00f6zelle\u015ftirmeler, onu daha g\u00fc\u00e7l\u00fc bir alternatif haline getirebilir.\n<\/p>\n<p>\n    <strong>Senaryo:<\/strong> Bir e-ticaret platformunun \u00fcretim sunucusunda, uygulaman\u0131n ani yava\u015flamalar ya\u015fad\u0131\u011f\u0131 rapor edildi. Uzak sunucuya SSH ile ba\u011fland\u0131n\u0131z ve ana uygulama log dosyas\u0131n\u0131n (<code>app.log<\/code>) boyutunun 50 GB'a ula\u015ft\u0131\u011f\u0131n\u0131 fark ettiniz. Bu dosyay\u0131 yerel makinenize indirmek hem zaman al\u0131c\u0131 hem de pratik de\u011fil. Mevcut Go metin g\u00f6r\u00fcnt\u00fcleyicinizle bu dosyay\u0131 direkt sunucu \u00fczerinden incelemeniz gerekiyor.\n<\/p>\n<p>\n    <strong>Mevcut Go G\u00f6r\u00fcnt\u00fcleyicimizin Faydalar\u0131:<\/strong>\n<\/p>\n<ol>\n<li>\n        <strong>H\u0131zl\u0131 Ba\u015flang\u0131\u00e7 ve D\u00fc\u015f\u00fck Bellek T\u00fcketimi:<\/strong> Geli\u015ftirdi\u011fimiz \"lazy loading\" mekanizmas\u0131 sayesinde, g\u00f6r\u00fcnt\u00fcleyici 50 GB'l\u0131k dosyay\u0131 an\u0131nda a\u00e7abilir \u00e7\u00fcnk\u00fc t\u00fcm i\u00e7eri\u011fi belle\u011fe y\u00fcklemez. Yaln\u0131zca sat\u0131r indekslerini bellekte tutar ve g\u00f6r\u00fcnt\u00fclenecek sat\u0131rlar\u0131 gerekti\u011finde diskten okur. Bu, s\u0131n\u0131rl\u0131 belle\u011fe sahip sunucu ortamlar\u0131 i\u00e7in hayati \u00f6nem ta\u015f\u0131r.<\/p>\n<pre><code>\n        # Go metin g\u00f6r\u00fcnt\u00fcleyicimizi sunucuya y\u00fckleyip \u00e7al\u0131\u015ft\u0131ral\u0131m\n        .\/go-text-viewer app.log\n        <\/pre>\n<p><\/code><br \/>\n        Bu komut ile g\u00f6r\u00fcnt\u00fcleyici saniyeler i\u00e7inde a\u00e7\u0131lacak ve log dosyas\u0131n\u0131n ilk sat\u0131rlar\u0131n\u0131 g\u00f6sterecektir.\n    <\/li>\n<li>\n        <strong>Ak\u0131c\u0131 Navigasyon:<\/strong> <code>PageUp<\/code>, <code>PageDown<\/code>, yukar\u0131\/a\u015fa\u011f\u0131 ok tu\u015flar\u0131 ile dosya i\u00e7inde ak\u0131c\u0131 bir \u015fekilde gezinebilirsiniz. <code>offsetY<\/code> ve <code>offsetX<\/code> de\u011fi\u015fkenleri sayesinde, dosyan\u0131n herhangi bir yerine h\u0131zl\u0131ca atlayabilir ve yatay olarak da kayd\u0131rabilirsiniz, bu da uzun log sat\u0131rlar\u0131n\u0131 okurken \u00e7ok kullan\u0131\u015fl\u0131d\u0131r. \u00d6rne\u011fin, belirli bir hata mesaj\u0131 veya zaman damgas\u0131 ararken h\u0131zl\u0131ca ilgili b\u00f6lgeye gitmek paha bi\u00e7ilmezdir.\n    <\/li>\n<li>\n        <strong>Sat\u0131r Numaralar\u0131 ve Durum \u00c7ubu\u011fu:<\/strong> Ekledi\u011fimiz sat\u0131r numaralar\u0131, hangi log olay\u0131nda oldu\u011funuzu takip etmenize yard\u0131mc\u0131 olur. \u00dcstteki durum \u00e7ubu\u011fu ise dosya ad\u0131n\u0131, mevcut sat\u0131r numaras\u0131n\u0131 ve toplam sat\u0131r say\u0131s\u0131n\u0131 g\u00f6stererek size s\u00fcrekli bilgi sa\u011flar. Bu, birden fazla ekip \u00fcyesiyle bir sorunu tart\u0131\u015f\u0131rken \"52432. sat\u0131ra bak\" gibi referanslar vermenizi kolayla\u015ft\u0131r\u0131r.\n    <\/li>\n<\/ol>\n<p>\n    <strong>Geli\u015ftirilebilecek \u00d6zellikler (\u0130leri D\u00fczey \u0130pu\u00e7lar\u0131):<\/strong>\n<\/p>\n<ul>\n<li>\n        <strong>Arama Fonksiyonu:<\/strong> B\u00fcy\u00fck log dosyalar\u0131nda belirli anahtar kelimeleri veya kal\u0131plar\u0131 bulmak i\u00e7in g\u00fc\u00e7l\u00fc bir arama (regex destekli) \u00f6zelli\u011fi eklemek, g\u00f6r\u00fcnt\u00fcleyicinin de\u011ferini katlayacakt\u0131r. Bu, \u00f6zellikle hata kodlar\u0131 veya kullan\u0131c\u0131 kimlikleri ararken \u00e7ok faydal\u0131d\u0131r.<\/p>\n<pre><code>\n        \/\/ Pseudo-kod: Arama fonksiyonu\n        func (vs *ViewerState) Search(query string) {\n            \/\/ regex derle\n            \/\/ mevcut offsetY'den ba\u015flayarak her sat\u0131r\u0131 oku\n            \/\/ e\u015fle\u015fme buldu\u011funda offsetY'i g\u00fcncelle ve Draw() \u00e7a\u011f\u0131r\n        }\n        <\/pre>\n<p><\/code>\n    <\/li>\n<li>\n        <strong>Renklendirme (Syntax Highlighting):<\/strong> Log seviyelerine (ERROR, WARN, INFO) veya belirli kal\u0131plara g\u00f6re sat\u0131rlar\u0131 renklendirmek, \u00f6nemli bilgilerin g\u00f6rsel olarak daha h\u0131zl\u0131 fark edilmesini sa\u011flar. \u00d6rne\u011fin, \"ERROR\" i\u00e7eren sat\u0131rlar\u0131 k\u0131rm\u0131z\u0131 yapmak.<\/p>\n<pre><code>\n        \/\/ Renklendirme stili uygulama \u00f6rne\u011fi\n        errorStyle := tcell.StyleDefault.Background(tcell.ColorBlack).Foreground(tcell.ColorRed)\n        if strings.Contains(lineContent, \"ERROR\") {\n            vs.putText(lineNumWidth, y, errorStyle, displayLine)\n        } else {\n            vs.putText(lineNumWidth, y, defStyle, displayLine)\n        }\n        <\/pre>\n<p><\/code>\n    <\/li>\n<li>\n        <strong>G Bookmark (\u0130\u015faretleme):<\/strong> \u00d6nemli sat\u0131rlar\u0131 i\u015faretleyip daha sonra bu i\u015faretli sat\u0131rlara h\u0131zl\u0131ca geri d\u00f6nebilme \u00f6zelli\u011fi, karma\u015f\u0131k analizler yaparken verimlili\u011fi art\u0131r\u0131r.\n    <\/li>\n<li>\n        <strong>Goto Line (Belirli Sat\u0131ra Git):<\/strong> Kullan\u0131c\u0131n\u0131n do\u011frudan belirli bir sat\u0131r numaras\u0131na atlamas\u0131na olanak tan\u0131yan bir komut istemi.\n    <\/li>\n<\/ul>\n<p>\n    Bu vaka analizi, geli\u015ftirdi\u011fimiz Go tabanl\u0131 metin g\u00f6r\u00fcnt\u00fcleyicisinin sadece bir \"hobby projesi\" olman\u0131n \u00f6tesinde, ger\u00e7ek d\u00fcnya sorunlar\u0131na etkili \u00e7\u00f6z\u00fcmler sunabilece\u011fini g\u00f6stermektedir. Go'nun performans yetenekleri ve <code>tcell<\/code> gibi k\u00fct\u00fcphanelerin sa\u011flad\u0131\u011f\u0131 esneklik sayesinde, geli\u015ftiriciler kendi ihtiya\u00e7lar\u0131na \u00f6zel, g\u00fc\u00e7l\u00fc terminal ara\u00e7lar\u0131 olu\u015fturabilirler. Bu, geli\u015ftirici verimlili\u011fini art\u0131ran ve karma\u015f\u0131k sistemleri daha iyi anlamam\u0131z\u0131 sa\u011flayan paha bi\u00e7ilmez bir yetenektir. \u00d6zellikle DevOps ekipleri ve sistem y\u00f6neticileri i\u00e7in, b\u00f6yle bir ara\u00e7 kutular\u0131ndaki \u00f6nemli bir silah olacakt\u0131r.\n<\/p>\n<h2>Go Metin G\u00f6r\u00fcnt\u00fcleyicileri i\u00e7in Performans Optimizasyonu ve \u0130leri \u0130pu\u00e7lar\u0131 Nelerdir?<\/h2>\n<p>\n    Go ile geli\u015ftirdi\u011fimiz metin g\u00f6r\u00fcnt\u00fcleyicinin temel i\u015flevselli\u011fini olu\u015ftursak da, onu ger\u00e7ek anlamda g\u00fc\u00e7l\u00fc ve kullan\u0131\u015fl\u0131 bir ara\u00e7 haline getirmek i\u00e7in performans optimizasyonlar\u0131na ve ileri d\u00fczey \u00f6zelliklere odaklanmak gerekir. \u00d6zellikle \u00e7ok b\u00fcy\u00fck dosyalarla veya \u00e7oklu terminal ba\u011flant\u0131lar\u0131 \u00fczerinden \u00e7al\u0131\u015f\u0131rken performans kritik bir hale gelir.\n<\/p>\n<h3>Ekran Yenileme S\u0131kl\u0131\u011f\u0131n\u0131 ve \u00c7izim Mant\u0131\u011f\u0131n\u0131 Optimize Etme<\/h3>\n<p>\n    Her klavye bas\u0131m\u0131nda veya olayda t\u00fcm ekran\u0131 temizleyip yeniden \u00e7izmek, basit uygulamalar i\u00e7in kabul edilebilir olsa da, daha karma\u015f\u0131k veya yo\u011fun i\u015flem gerektiren senaryolarda performans\u0131 d\u00fc\u015f\u00fcrebilir.\n<\/p>\n<ol>\n<li>\n        <strong>K\u0131smi Yenileme (Partial Redraw):<\/strong> Yaln\u0131zca de\u011fi\u015fen b\u00f6lgeleri yeniden \u00e7izin. \u00d6rne\u011fin, kullan\u0131c\u0131 sadece bir sat\u0131r yukar\u0131 kayd\u0131rd\u0131\u011f\u0131nda, t\u00fcm ekran\u0131 yeniden \u00e7izmek yerine sadece kayan i\u00e7eri\u011fi ve yeni g\u00f6r\u00fcnen sat\u0131r\u0131 \u00e7izmek daha verimli olacakt\u0131r. Ancak <code>tcell<\/code> genellikle bu optimizasyonlar\u0131 kendi i\u00e7inde bir miktar yapar, yine de <code>screen.Show()<\/code> \u00e7a\u011fr\u0131s\u0131n\u0131 m\u00fcmk\u00fcn oldu\u011funca minimumda tutmaya \u00e7al\u0131\u015f\u0131n.\n    <\/li>\n<li>\n        <strong>\u00c7ift Arabelleyicili (Double Buffering):<\/strong> <code>tcell<\/code>, zaten varsay\u0131lan olarak \u00e7ift arabelleyicili bir yakla\u015f\u0131mla \u00e7al\u0131\u015f\u0131r, bu da ekran titremesini (flickering) en aza indirir. Bu nedenle, ekranda \u00e7izim yaparken do\u011frudan terminale de\u011fil, bir arka arabelle\u011fe \u00e7izim yap\u0131l\u0131r ve ard\u0131ndan tek bir i\u015flemle ekrana aktar\u0131l\u0131r.\n    <\/li>\n<li>\n        <strong>Gecikmeli Yenileme (Debouncing\/Throttling):<\/strong> \u00d6zellikle pencere yeniden boyutland\u0131rma gibi s\u0131k tetiklenebilecek olaylarda, <code>Draw()<\/code> fonksiyonunu an\u0131nda \u00e7a\u011f\u0131rmak yerine, k\u00fc\u00e7\u00fck bir gecikme ekleyerek (\u00f6rne\u011fin 50ms) birden fazla olay\u0131 tek bir \u00e7izim i\u015flemiyle birle\u015ftirebilirsiniz. Bu, CPU kullan\u0131m\u0131n\u0131 azalt\u0131r.\n    <\/li>\n<\/ol>\n<h3>B\u00fcy\u00fck Dosyalar i\u00e7in Bellek Y\u00f6netimi ve Disk I\/O \u0130yile\u015ftirmeleri<\/h3>\n<p>\n    Daha \u00f6nce bahsetti\u011fimiz lazy loading yakla\u015f\u0131m\u0131n\u0131 daha da geli\u015ftirebiliriz:\n<\/p>\n<ol>\n<li>\n        <strong>Daha Ak\u0131ll\u0131 Sat\u0131r \u0130ndeksleme:<\/strong> \u00c7ok b\u00fcy\u00fck dosyalarda (terabaytlarca), sat\u0131r indeksi (<code>lineInfos<\/code>) bile bellekte \u00e7ok yer kaplayabilir. Bu durumda, dosyan\u0131n tamam\u0131n\u0131 indekslemek yerine, ilk N sat\u0131r\u0131 ve belirli aral\u0131klarla \"checkpoint\" sat\u0131rlar\u0131n\u0131 indeksleyerek genel indeks boyutunu azaltabiliriz. Kullan\u0131c\u0131 bir checkpoint d\u0131\u015f\u0131ndaki bir sat\u0131ra atlamak istedi\u011finde, o checkpoint'ten itibaren ileri do\u011fru okuma yaparak hedef sat\u0131r\u0131 buluruz.\n    <\/li>\n<li>\n        <strong><code>mmap<\/code> Kullan\u0131m\u0131:<\/strong> Unix benzeri sistemlerde <code>syscall.Mmap<\/code> kullanarak dosyay\u0131 do\u011frudan belle\u011fe e\u015fle\u015ftirmek (memory-mapping), b\u00fcy\u00fck dosyalar \u00fczerinde I\/O i\u015flemlerini \u00f6nemli \u00f6l\u00e7\u00fcde h\u0131zland\u0131rabilir. Bu, dosya i\u00e7eri\u011finin i\u015fletim sistemi taraf\u0131ndan gerekti\u011finde belle\u011fe getirilmesini sa\u011flar ve manuel <code>Seek<\/code>\/<code>Read<\/code> i\u015flemlerinden daha verimli olabilir.<\/p>\n<pre><code>\n        \/\/ \u00d6rnek mmap kullan\u0131m\u0131 (basitle\u015ftirilmi\u015f)\n        import (\n        \t\"syscall\"\n        \t\"os\"\n        )\n        \n        func mapFile(filePath string) ([]byte, error) {\n        \tfile, err := os.Open(filePath)\n        \tif err != nil {\n        \t\treturn nil, err\n        \t}\n        \tdefer file.Close()\n        \n        \tfileInfo, err := file.Stat()\n        \tif err != nil {\n        \t\treturn nil, err\n        \t}\n        \tfileSize := int(fileInfo.Size())\n        \n        \t\/\/ Dosyay\u0131 belle\u011fe e\u015fle\n        \tdata, err := syscall.Mmap(int(file.Fd()), 0, fileSize, syscall.PROT_READ, syscall.MAP_SHARED)\n        \tif err != nil {\n        \t\treturn nil, err\n        \t}\n        \treturn data, nil\n        }\n        <\/pre>\n<p><\/code><br \/>\n        Bu yakla\u015f\u0131m, dosyan\u0131n do\u011frudan bir bayt dilimi gibi davranmas\u0131n\u0131 sa\u011flar ve <code>GetLineContent<\/code> metodunu basitle\u015ftirebilir. Ancak dikkatli olunmal\u0131, \u00e7\u00fcnk\u00fc <code>mmap<\/code> kullan\u0131m\u0131 platforma \u00f6zg\u00fcd\u00fcr ve hata y\u00f6netimi karma\u015f\u0131k olabilir.\n    <\/li>\n<li>\n        <strong>Arabellek Havuzu (Buffer Pool):<\/strong> <code>GetLineContent<\/code> gibi s\u0131k \u00e7a\u011fr\u0131lan fonksiyonlar i\u00e7in s\u00fcrekli yeni bellek ay\u0131rmaktan (<code>make([]byte, ...)<\/code>) ka\u00e7\u0131n\u0131n. <code>sync.Pool<\/code> kullanarak bayt arabelleklerini yeniden kullanmak, \u00e7\u00f6p toplama (garbage collection) y\u00fck\u00fcn\u00fc azaltarak performans\u0131 art\u0131rabilir.\n    <\/li>\n<\/ol>\n<aside class=\"expert-tip\">\n    Uzman \u0130pucu: Profilleme (profiling), performans sorunlar\u0131n\u0131n k\u00f6k nedenini bulmak i\u00e7in en iyi yoldur. Go'nun yerle\u015fik pprof arac\u0131 (<code>go tool pprof<\/code>) ile uygulaman\u0131z\u0131n CPU, bellek ve bloklama profillerini analiz edebilir, darbo\u011fazlar\u0131 tespit edip optimize edebilirsiniz. \u00d6l\u00e7meden optimize etmeyin!<br \/>\n<\/aside>\n<h3>Geli\u015fmi\u015f \u00d6zellikler ve Kullan\u0131c\u0131 Deneyimi<\/h3>\n<p>\n    Sadece performans de\u011fil, kullan\u0131c\u0131 deneyimini zenginle\u015ftirecek \u00f6zellikler de \u00f6nemlidir:\n<\/p>\n<ul>\n<li>\n        <strong>Arama ve Regex Deste\u011fi:<\/strong> <code>regexp<\/code> paketi kullanarak g\u00fc\u00e7l\u00fc ve esnek metin arama yetenekleri ekleyin. E\u015fle\u015fmeleri renklendirmek ve arama sonu\u00e7lar\u0131 aras\u0131nda gezinmek, log dosyalar\u0131n\u0131 incelerken \u00e7ok zaman kazand\u0131r\u0131r.\n    <\/li>\n<li>\n        <strong>Sat\u0131r Atlatma (Jump to Line):<\/strong> Kullan\u0131c\u0131n\u0131n do\u011frudan belirli bir sat\u0131r numaras\u0131na gitmesini sa\u011flayan bir komut istemi (\u00f6rne\u011fin, <code>:123<\/code> gibi).\n    <\/li>\n<li>\n        <strong>Metin Kopyalama (Clipboard Integration):<\/strong> Terminal uygulamalar\u0131nda do\u011frudan panoya kopyalama genellikle zordur ve terminal em\u00fclat\u00f6r\u00fcn\u00fcn \u00f6zelliklerine ba\u011fl\u0131d\u0131r. Ancak, baz\u0131 k\u00fct\u00fcphaneler (\u00f6rne\u011fin <code>github.com\/atotto\/clipboard<\/code>) platforma \u00f6zg\u00fc \u00e7\u00f6z\u00fcmler sunabilir.\n    <\/li>\n<li>\n        <strong>Yap\u0131land\u0131rma Dosyas\u0131:<\/strong> Kullan\u0131c\u0131lar\u0131n varsay\u0131lan renk \u015femalar\u0131n\u0131, klavye k\u0131sayollar\u0131n\u0131 veya di\u011fer tercihleri bir yap\u0131land\u0131rma dosyas\u0131 (\u00f6rne\u011fin YAML, TOML) arac\u0131l\u0131\u011f\u0131yla \u00f6zelle\u015ftirmesine olanak tan\u0131y\u0131n. Bu, <code>github.com\/spf13\/viper<\/code> gibi k\u00fct\u00fcphanelerle kolayca yap\u0131labilir.\n    <\/li>\n<li>\n        <strong>Dosya \u0130zleme (Follow Mode - <code>tail -f<\/code> benzeri):<\/strong> Dosya sonuna otomatik olarak kayd\u0131rma ve dosyan\u0131n de\u011fi\u015fmesini bekleyerek yeni i\u00e7erikleri an\u0131nda g\u00f6sterme \u00f6zelli\u011fi, ger\u00e7ek zamanl\u0131 log izleme i\u00e7in \u00e7ok \u00f6nemlidir. Bu, <code>fsnotify<\/code> gibi k\u00fct\u00fcphanelerle veya d\u00fczenli aral\u0131klarla dosya boyutunu kontrol ederek uygulanabilir.\n    <\/li>\n<\/ul>\n<p>\n    Bu ileri d\u00fczey ipu\u00e7lar\u0131 ve optimizasyonlar, Go ile yazd\u0131\u011f\u0131n\u0131z metin g\u00f6r\u00fcnt\u00fcleyicisini sadece i\u015flevsel de\u011fil, ayn\u0131 zamanda zorlu ortamlar ve kullan\u0131m senaryolar\u0131 i\u00e7in de sa\u011flam ve performansl\u0131 bir ara\u00e7 haline getirecektir. Unutmay\u0131n ki, her optimizasyonun bir maliyeti vard\u0131r; bu nedenle, en b\u00fcy\u00fck etkiyi sa\u011flayacak ve uygulaman\u0131z\u0131n temel amac\u0131na hizmet edecek iyile\u015ftirmelere odaklanmak her zaman en iyisidir.\n<\/p>\n<h2>Sonu\u00e7 ve S\u0131k\u00e7a Sorulan Sorular<\/h2>\n<p>\n    Bu makalede, Go programlama dilini ve <code>tcell<\/code> k\u00fct\u00fcphanesini kullanarak konsol tabanl\u0131 bir metin g\u00f6r\u00fcnt\u00fcleyici olu\u015fturman\u0131n temel ad\u0131mlar\u0131n\u0131 ve ileri d\u00fczey tekniklerini detayl\u0131ca inceledik. S\u0131f\u0131rdan ba\u015flayarak, dosya okuma, ekran \u00e7izimi, kullan\u0131c\u0131 etkile\u015fimi y\u00f6netimi ve b\u00fcy\u00fck dosyalar i\u00e7in performans optimizasyonu gibi konular\u0131 ele ald\u0131k. Geli\u015ftirdi\u011fimiz bu ara\u00e7, SSH \u00fczerinden uzak sunucularda veya minimalist ortamlarda b\u00fcy\u00fck log dosyalar\u0131n\u0131 incelemek gibi ger\u00e7ek d\u00fcnya senaryolar\u0131nda paha bi\u00e7ilmez bir yard\u0131mc\u0131 olabilir. Go'nun performans\u0131 ve <code>tcell<\/code>'in esnekli\u011fi sayesinde, g\u00fc\u00e7l\u00fc ve \u00f6zelle\u015ftirilebilir bir terminal uygulamas\u0131 in\u015fa etmenin ne kadar eri\u015filebilir oldu\u011funu g\u00f6rd\u00fck.\n<\/p>\n<p>\n    Bu proje, sadece bir metin g\u00f6r\u00fcnt\u00fcleyici olu\u015fturmakla kalmay\u0131p, ayn\u0131 zamanda Go ile interaktif terminal uygulamalar\u0131 geli\u015ftirme konusunda sa\u011flam bir temel olu\u015fturman\u0131z\u0131 sa\u011flam\u0131\u015ft\u0131r. Edindi\u011finiz bu bilgilerle, kendi ihtiya\u00e7lar\u0131n\u0131za g\u00f6re daha geli\u015fmi\u015f \u00f6zellikler (arama, renklendirme, dosya izleme vb.) ekleyebilir ve arac\u0131n\u0131z\u0131 daha da ileriye ta\u015f\u0131yabilirsiniz. Konsol tabanl\u0131 ara\u00e7lar, h\u0131zlar\u0131, kaynak verimlilikleri ve evrensellikleri nedeniyle modern geli\u015ftirme ve sistem y\u00f6netimi i\u015f ak\u0131\u015flar\u0131nda her zaman kritik bir role sahip olacakt\u0131r.\n<\/p>\n<h3>S\u0131k\u00e7a Sorulan Sorular<\/h3>\n<dl>\n<dt>Go ile neden GUI tabanl\u0131 bir metin edit\u00f6r\u00fc yerine konsol tabanl\u0131 bir g\u00f6r\u00fcnt\u00fcleyici tercih etmeliyim?<\/dt>\n<dd>Konsol tabanl\u0131 g\u00f6r\u00fcnt\u00fcleyiciler, \u00f6zellikle uzak sunucu ortamlar\u0131nda SSH \u00fczerinden eri\u015firken, GUI'nin olmad\u0131\u011f\u0131 veya a\u011f\u0131r oldu\u011fu durumlarda \u00e7ok daha h\u0131zl\u0131 ve kaynak dostudur. Ayr\u0131ca, d\u00fc\u015f\u00fck gecikme s\u00fcresi ile an\u0131nda tepki verirler ve klavye odakl\u0131 kullan\u0131c\u0131lar i\u00e7in daha verimli bir deneyim sunabilirler. Go'nun \u00e7apraz platform yetene\u011fi sayesinde tek bir derlenmi\u015f ikili dosya ile farkl\u0131 sistemlerde sorunsuz \u00e7al\u0131\u015f\u0131rlar.<\/dd>\n<dt><code>tcell<\/code> k\u00fct\u00fcphanesi yerine ba\u015fka hangi Go k\u00fct\u00fcphanelerini kullanabilirim?<\/dt>\n<dd><code>tcell<\/code> pop\u00fcler ve modern bir se\u00e7enek olsa da, <code>termbox-go<\/code> da terminal aray\u00fczleri olu\u015fturmak i\u00e7in kullan\u0131lan bir ba\u015fka k\u00fct\u00fcphanedir. Her ikisi de benzer i\u015flevsellikler sunar; ancak <code>tcell<\/code> genellikle daha aktif olarak geli\u015ftirilir ve daha zengin \u00f6zellik setine (\u00f6rne\u011fin daha iyi Unicode deste\u011fi, fare olaylar\u0131) sahiptir. Se\u00e7im, projenizin spesifik ihtiya\u00e7lar\u0131na ve tercih etti\u011finiz API tasar\u0131m\u0131na g\u00f6re de\u011fi\u015febilir.<\/dd>\n<dt>B\u00fcy\u00fck log dosyalar\u0131nda arama yapmak i\u00e7in hangi Go paketini kullanmal\u0131y\u0131m?<\/dt>\n<dd>Go'nun standart k\u00fct\u00fcphanesindeki <code>regexp<\/code> paketi, d\u00fczenli ifade (regex) tabanl\u0131 g\u00fc\u00e7l\u00fc metin arama yetenekleri sunar. B\u00fcy\u00fck dosyalarda arama yaparken, t\u00fcm dosyay\u0131 belle\u011fe almaktan ka\u00e7\u0131nmak ve sadece arama yap\u0131lan b\u00f6l\u00fcm\u00fc okumak i\u00e7in \"lazy loading\" mekanizmas\u0131n\u0131 <code>regexp<\/code> ile birlikte kullanmak en iyi performans\u0131 sa\u011flar.<\/dd>\n<dt>Uygulamam\u0131n mobil cihazlarda \u00e7al\u0131\u015fmas\u0131n\u0131 sa\u011flayabilir miyim?<\/dt>\n<dd>Go ile yaz\u0131lan konsol uygulamalar\u0131, mobil cihazlarda do\u011frudan \u00e7al\u0131\u015facak \u015fekilde tasarlanmam\u0131\u015ft\u0131r. Ancak, Android veya iOS cihazlarda terminal em\u00fclat\u00f6rleri (Termux gibi) kullan\u0131l\u0131yorsa, Go uygulaman\u0131z bu em\u00fclat\u00f6rler i\u00e7erisinde derlenip \u00e7al\u0131\u015ft\u0131r\u0131labilir. Makaledeki \"mobil uyumlu HTML\" k\u0131sm\u0131, bu makalenin kendisinin bir web sayfas\u0131nda g\u00f6r\u00fcnt\u00fclendi\u011finde mobil cihazlarda iyi g\u00f6r\u00fcnmesini sa\u011flamaya y\u00f6neliktir, Go uygulamas\u0131n\u0131n kendisi i\u00e7in de\u011fil. Makalenin mobil uyumlulu\u011funu sa\u011flamak i\u00e7in HTML'de <code><meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\"><\/code> etiketi kullanmak ve CSS ile duyarl\u0131 tasar\u0131m (responsive design) ilkelerini uygulamak \u00f6nemlidir.<\/dd>\n<dt>Uygulamam\u0131 daha kolay da\u011f\u0131t\u0131labilir hale getirmek i\u00e7in ne yapmal\u0131y\u0131m?<\/dt>\n<dd>Go, derlenmi\u015f ikili dosyalar \u00fcretti\u011fi i\u00e7in da\u011f\u0131t\u0131m kolayd\u0131r. Uygulaman\u0131z\u0131 derlemek i\u00e7in <code>go build -o myviewer<\/code> komutunu kullanabilirsiniz. \u00c7apraz platform derleme i\u00e7in (\u00f6rne\u011fin Linux \u00fczerinde Windows i\u00e7in derleme), <code>GOOS<\/code> ve <code>GOARCH<\/code> ortam de\u011fi\u015fkenlerini kullanabilirsiniz (\u00f6rne\u011fin, <code>GOOS=windows GOARCH=amd64 go build -o myviewer.exe<\/code>). Bu, hedef platforma \u00f6zel derlenmi\u015f ikili dosyalar olu\u015fturman\u0131z\u0131 sa\u011flar ve ba\u011f\u0131ml\u0131l\u0131k y\u00f6netimi derleyici taraf\u0131ndan halledilir. Statik olarak derlenmi\u015f bu ikili dosyalar\u0131 hedef sisteme kopyalaman\u0131z yeterlidir.<\/dd>\n<\/dl>\n<p><\/body><\/p>\n","protected":false},"excerpt":{"rendered":"Go programlama dili kullanarak kendi konsol tabanl\u0131 metin g\u00f6r\u00fcnt\u00fcleyicinizi geli\u015ftirmek ister misiniz? Bu detayl\u0131 rehberde, s\u0131f\u0131rdan ba\u015flayarak g\u00fc\u00e7l\u00fc&hellip;","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"csco_page_header_type":"","csco_page_load_nextpost":"","csco_page_subscribe_form":"","csco_page_contact_form":"","footnotes":""},"categories":[1],"tags":[],"class_list":{"0":"post-34219","1":"post","2":"type-post","3":"status-publish","4":"format-standard","6":"category-genel","7":"cs-entry","8":"cs-video-wrap"},"yoast_head":"<!-- This site is optimized with the Yoast SEO Premium plugin v20.5 (Yoast SEO v25.3.1) - https:\/\/yoast.com\/wordpress\/plugins\/seo\/ -->\n<title>Go ile Konsol Tabanl\u0131 Metin G\u00f6r\u00fcnt\u00fcleyici Nas\u0131l Yap\u0131l\u0131r?<\/title>\n<meta name=\"description\" content=\"Go programlama dili kullanarak kendi konsol tabanl\u0131 metin g\u00f6r\u00fcnt\u00fcleyicinizi geli\u015ftirmek ister misiniz? Bu detayl\u0131 rehberde, s\u0131f\u0131rdan ba\u015flayarak g\u00fc\u00e7l\u00fc ve verimli bir metin g\u00f6r\u00fcnt\u00fcleyici olu\u015fturman\u0131n ad\u0131mlar\u0131n\u0131 ke\u015ffedecek, b\u00fcy\u00fck dosyalar\u0131 kolayca incelemenizi sa\u011flayacak teknikleri ve ipu\u00e7lar\u0131n\u0131 \u00f6\u011freneceksiniz. Modern geli\u015ftirme ortamlar\u0131nda s\u0131kl\u0131kla kar\u015f\u0131la\u015f\u0131lan bu ihtiyaca y\u00f6nelik pratik \u00e7\u00f6z\u00fcmlerle, Go&#039;nun performans\u0131n\u0131 ve sadeli\u011fini bir araya getiren bir ara\u00e7 in\u015fa edece\u011fiz.\" \/>\n<meta name=\"robots\" content=\"index, follow, max-snippet:-1, max-image-preview:large, max-video-preview:-1\" \/>\n<link rel=\"canonical\" href=\"https:\/\/fatihsoysal.com\/blog\/go-ile-konsol-tabanli-metin-goruntuleyici-nasil-yapilir\/\" \/>\n<meta property=\"og:locale\" content=\"tr_TR\" \/>\n<meta property=\"og:type\" content=\"article\" \/>\n<meta property=\"og:title\" content=\"Go ile Konsol Tabanl\u0131 Metin G\u00f6r\u00fcnt\u00fcleyici Nas\u0131l Yap\u0131l\u0131r?\" \/>\n<meta property=\"og:description\" content=\"Go programlama dili kullanarak kendi konsol tabanl\u0131 metin g\u00f6r\u00fcnt\u00fcleyicinizi geli\u015ftirmek ister misiniz? Bu detayl\u0131 rehberde, s\u0131f\u0131rdan ba\u015flayarak g\u00fc\u00e7l\u00fc ve verimli bir metin g\u00f6r\u00fcnt\u00fcleyici olu\u015fturman\u0131n ad\u0131mlar\u0131n\u0131 ke\u015ffedecek, b\u00fcy\u00fck dosyalar\u0131 kolayca incelemenizi sa\u011flayacak teknikleri ve ipu\u00e7lar\u0131n\u0131 \u00f6\u011freneceksiniz. Modern geli\u015ftirme ortamlar\u0131nda s\u0131kl\u0131kla kar\u015f\u0131la\u015f\u0131lan bu ihtiyaca y\u00f6nelik pratik \u00e7\u00f6z\u00fcmlerle, Go&#039;nun performans\u0131n\u0131 ve sadeli\u011fini bir araya getiren bir ara\u00e7 in\u015fa edece\u011fiz.\" \/>\n<meta property=\"og:url\" content=\"https:\/\/fatihsoysal.com\/blog\/go-ile-konsol-tabanli-metin-goruntuleyici-nasil-yapilir\/\" \/>\n<meta property=\"og:site_name\" content=\"Kodlar\u0131n Gizemli D\u00fcnyas\u0131\" \/>\n<meta property=\"article:published_time\" content=\"2025-11-13T01:31:27+00:00\" \/>\n<meta name=\"author\" content=\"Fatih Soysal\" \/>\n<meta name=\"twitter:card\" content=\"summary_large_image\" \/>\n<meta name=\"twitter:label1\" content=\"Yazan:\" \/>\n\t<meta name=\"twitter:data1\" content=\"Fatih Soysal\" \/>\n\t<meta name=\"twitter:label2\" content=\"Tahmini okuma s\u00fcresi\" \/>\n\t<meta name=\"twitter:data2\" content=\"36 dakika\" \/>\n<script type=\"application\/ld+json\" class=\"yoast-schema-graph\">{\"@context\":\"https:\/\/schema.org\",\"@graph\":[{\"@type\":\"Article\",\"@id\":\"https:\/\/fatihsoysal.com\/blog\/go-ile-konsol-tabanli-metin-goruntuleyici-nasil-yapilir\/#article\",\"isPartOf\":{\"@id\":\"https:\/\/fatihsoysal.com\/blog\/go-ile-konsol-tabanli-metin-goruntuleyici-nasil-yapilir\/\"},\"author\":{\"name\":\"Fatih Soysal\",\"@id\":\"https:\/\/fatihsoysal.com\/blog\/#\/schema\/person\/002a254750921dcfd568a99e48240dd1\"},\"headline\":\"Go ile Konsol Tabanl\u0131 Metin G\u00f6r\u00fcnt\u00fcleyici Nas\u0131l Yap\u0131l\u0131r?\",\"datePublished\":\"2025-11-13T01:31:27+00:00\",\"mainEntityOfPage\":{\"@id\":\"https:\/\/fatihsoysal.com\/blog\/go-ile-konsol-tabanli-metin-goruntuleyici-nasil-yapilir\/\"},\"wordCount\":4784,\"commentCount\":0,\"publisher\":{\"@id\":\"https:\/\/fatihsoysal.com\/blog\/#\/schema\/person\/002a254750921dcfd568a99e48240dd1\"},\"inLanguage\":\"tr\",\"potentialAction\":[{\"@type\":\"CommentAction\",\"name\":\"Comment\",\"target\":[\"https:\/\/fatihsoysal.com\/blog\/go-ile-konsol-tabanli-metin-goruntuleyici-nasil-yapilir\/#respond\"]}],\"copyrightYear\":\"2025\",\"copyrightHolder\":{\"@id\":\"https:\/\/fatihsoysal.com\/blog\/#organization\"}},{\"@type\":\"WebPage\",\"@id\":\"https:\/\/fatihsoysal.com\/blog\/go-ile-konsol-tabanli-metin-goruntuleyici-nasil-yapilir\/\",\"url\":\"https:\/\/fatihsoysal.com\/blog\/go-ile-konsol-tabanli-metin-goruntuleyici-nasil-yapilir\/\",\"name\":\"Go ile Konsol Tabanl\u0131 Metin G\u00f6r\u00fcnt\u00fcleyici Nas\u0131l Yap\u0131l\u0131r?\",\"isPartOf\":{\"@id\":\"https:\/\/fatihsoysal.com\/blog\/#website\"},\"datePublished\":\"2025-11-13T01:31:27+00:00\",\"description\":\"Go programlama dili kullanarak kendi konsol tabanl\u0131 metin g\u00f6r\u00fcnt\u00fcleyicinizi geli\u015ftirmek ister misiniz? Bu detayl\u0131 rehberde, s\u0131f\u0131rdan ba\u015flayarak g\u00fc\u00e7l\u00fc ve verimli bir metin g\u00f6r\u00fcnt\u00fcleyici olu\u015fturman\u0131n ad\u0131mlar\u0131n\u0131 ke\u015ffedecek, b\u00fcy\u00fck dosyalar\u0131 kolayca incelemenizi sa\u011flayacak teknikleri ve ipu\u00e7lar\u0131n\u0131 \u00f6\u011freneceksiniz. Modern geli\u015ftirme ortamlar\u0131nda s\u0131kl\u0131kla kar\u015f\u0131la\u015f\u0131lan bu ihtiyaca y\u00f6nelik pratik \u00e7\u00f6z\u00fcmlerle, Go'nun performans\u0131n\u0131 ve sadeli\u011fini bir araya getiren bir ara\u00e7 in\u015fa edece\u011fiz.\",\"breadcrumb\":{\"@id\":\"https:\/\/fatihsoysal.com\/blog\/go-ile-konsol-tabanli-metin-goruntuleyici-nasil-yapilir\/#breadcrumb\"},\"inLanguage\":\"tr\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"https:\/\/fatihsoysal.com\/blog\/go-ile-konsol-tabanli-metin-goruntuleyici-nasil-yapilir\/\"]}]},{\"@type\":\"BreadcrumbList\",\"@id\":\"https:\/\/fatihsoysal.com\/blog\/go-ile-konsol-tabanli-metin-goruntuleyici-nasil-yapilir\/#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"name\":\"Anasayfa\",\"item\":\"https:\/\/fatihsoysal.com\/blog\/\"},{\"@type\":\"ListItem\",\"position\":2,\"name\":\"Go ile Konsol Tabanl\u0131 Metin G\u00f6r\u00fcnt\u00fcleyici Nas\u0131l Yap\u0131l\u0131r?\"}]},{\"@type\":\"WebSite\",\"@id\":\"https:\/\/fatihsoysal.com\/blog\/#website\",\"url\":\"https:\/\/fatihsoysal.com\/blog\/\",\"name\":\"Fatihsoysal.com\",\"description\":\"Blog - Yaz\u0131l\u0131m D\u00fcnyas\u0131 Tecr\u00fcbelerim\",\"publisher\":{\"@id\":\"https:\/\/fatihsoysal.com\/blog\/#\/schema\/person\/002a254750921dcfd568a99e48240dd1\"},\"potentialAction\":[{\"@type\":\"SearchAction\",\"target\":{\"@type\":\"EntryPoint\",\"urlTemplate\":\"https:\/\/fatihsoysal.com\/blog\/?s={search_term_string}\"},\"query-input\":{\"@type\":\"PropertyValueSpecification\",\"valueRequired\":true,\"valueName\":\"search_term_string\"}}],\"inLanguage\":\"tr\"},{\"@type\":[\"Person\",\"Organization\"],\"@id\":\"https:\/\/fatihsoysal.com\/blog\/#\/schema\/person\/002a254750921dcfd568a99e48240dd1\",\"name\":\"Fatih Soysal\",\"image\":{\"@type\":\"ImageObject\",\"inLanguage\":\"tr\",\"@id\":\"https:\/\/fatihsoysal.com\/blog\/#\/schema\/person\/image\/\",\"url\":\"https:\/\/fatihsoysal.com\/blog\/wp-content\/uploads\/2024\/04\/cropped-replicate-prediction-3kgg1hgjn5rgp0cf0p5tr0jw7w-1.png\",\"contentUrl\":\"https:\/\/fatihsoysal.com\/blog\/wp-content\/uploads\/2024\/04\/cropped-replicate-prediction-3kgg1hgjn5rgp0cf0p5tr0jw7w-1.png\",\"width\":512,\"height\":512,\"caption\":\"Fatih Soysal\"},\"logo\":{\"@id\":\"https:\/\/fatihsoysal.com\/blog\/#\/schema\/person\/image\/\"},\"description\":\"Kullan\u0131m ve kodlama m\u00fckemmeliyetini odak alan uygulamalar olu\u015fturma deneyimine sahip, profesyonel olarak 15+ y\u0131l \u00fczeri deneyime sahip bir yaz\u0131l\u0131m m\u00fchendisi.\",\"url\":\"https:\/\/fatihsoysal.com\/blog\/author\/fatihsoysal\/\"}]}<\/script>\n<!-- \/ Yoast SEO Premium plugin. -->","yoast_head_json":{"title":"Go ile Konsol Tabanl\u0131 Metin G\u00f6r\u00fcnt\u00fcleyici Nas\u0131l Yap\u0131l\u0131r?","description":"Go programlama dili kullanarak kendi konsol tabanl\u0131 metin g\u00f6r\u00fcnt\u00fcleyicinizi geli\u015ftirmek ister misiniz? Bu detayl\u0131 rehberde, s\u0131f\u0131rdan ba\u015flayarak g\u00fc\u00e7l\u00fc ve verimli bir metin g\u00f6r\u00fcnt\u00fcleyici olu\u015fturman\u0131n ad\u0131mlar\u0131n\u0131 ke\u015ffedecek, b\u00fcy\u00fck dosyalar\u0131 kolayca incelemenizi sa\u011flayacak teknikleri ve ipu\u00e7lar\u0131n\u0131 \u00f6\u011freneceksiniz. Modern geli\u015ftirme ortamlar\u0131nda s\u0131kl\u0131kla kar\u015f\u0131la\u015f\u0131lan bu ihtiyaca y\u00f6nelik pratik \u00e7\u00f6z\u00fcmlerle, Go'nun performans\u0131n\u0131 ve sadeli\u011fini bir araya getiren bir ara\u00e7 in\u015fa edece\u011fiz.","robots":{"index":"index","follow":"follow","max-snippet":"max-snippet:-1","max-image-preview":"max-image-preview:large","max-video-preview":"max-video-preview:-1"},"canonical":"https:\/\/fatihsoysal.com\/blog\/go-ile-konsol-tabanli-metin-goruntuleyici-nasil-yapilir\/","og_locale":"tr_TR","og_type":"article","og_title":"Go ile Konsol Tabanl\u0131 Metin G\u00f6r\u00fcnt\u00fcleyici Nas\u0131l Yap\u0131l\u0131r?","og_description":"Go programlama dili kullanarak kendi konsol tabanl\u0131 metin g\u00f6r\u00fcnt\u00fcleyicinizi geli\u015ftirmek ister misiniz? Bu detayl\u0131 rehberde, s\u0131f\u0131rdan ba\u015flayarak g\u00fc\u00e7l\u00fc ve verimli bir metin g\u00f6r\u00fcnt\u00fcleyici olu\u015fturman\u0131n ad\u0131mlar\u0131n\u0131 ke\u015ffedecek, b\u00fcy\u00fck dosyalar\u0131 kolayca incelemenizi sa\u011flayacak teknikleri ve ipu\u00e7lar\u0131n\u0131 \u00f6\u011freneceksiniz. Modern geli\u015ftirme ortamlar\u0131nda s\u0131kl\u0131kla kar\u015f\u0131la\u015f\u0131lan bu ihtiyaca y\u00f6nelik pratik \u00e7\u00f6z\u00fcmlerle, Go'nun performans\u0131n\u0131 ve sadeli\u011fini bir araya getiren bir ara\u00e7 in\u015fa edece\u011fiz.","og_url":"https:\/\/fatihsoysal.com\/blog\/go-ile-konsol-tabanli-metin-goruntuleyici-nasil-yapilir\/","og_site_name":"Kodlar\u0131n Gizemli D\u00fcnyas\u0131","article_published_time":"2025-11-13T01:31:27+00:00","author":"Fatih Soysal","twitter_card":"summary_large_image","twitter_misc":{"Yazan:":"Fatih Soysal","Tahmini okuma s\u00fcresi":"36 dakika"},"schema":{"@context":"https:\/\/schema.org","@graph":[{"@type":"Article","@id":"https:\/\/fatihsoysal.com\/blog\/go-ile-konsol-tabanli-metin-goruntuleyici-nasil-yapilir\/#article","isPartOf":{"@id":"https:\/\/fatihsoysal.com\/blog\/go-ile-konsol-tabanli-metin-goruntuleyici-nasil-yapilir\/"},"author":{"name":"Fatih Soysal","@id":"https:\/\/fatihsoysal.com\/blog\/#\/schema\/person\/002a254750921dcfd568a99e48240dd1"},"headline":"Go ile Konsol Tabanl\u0131 Metin G\u00f6r\u00fcnt\u00fcleyici Nas\u0131l Yap\u0131l\u0131r?","datePublished":"2025-11-13T01:31:27+00:00","mainEntityOfPage":{"@id":"https:\/\/fatihsoysal.com\/blog\/go-ile-konsol-tabanli-metin-goruntuleyici-nasil-yapilir\/"},"wordCount":4784,"commentCount":0,"publisher":{"@id":"https:\/\/fatihsoysal.com\/blog\/#\/schema\/person\/002a254750921dcfd568a99e48240dd1"},"inLanguage":"tr","potentialAction":[{"@type":"CommentAction","name":"Comment","target":["https:\/\/fatihsoysal.com\/blog\/go-ile-konsol-tabanli-metin-goruntuleyici-nasil-yapilir\/#respond"]}],"copyrightYear":"2025","copyrightHolder":{"@id":"https:\/\/fatihsoysal.com\/blog\/#organization"}},{"@type":"WebPage","@id":"https:\/\/fatihsoysal.com\/blog\/go-ile-konsol-tabanli-metin-goruntuleyici-nasil-yapilir\/","url":"https:\/\/fatihsoysal.com\/blog\/go-ile-konsol-tabanli-metin-goruntuleyici-nasil-yapilir\/","name":"Go ile Konsol Tabanl\u0131 Metin G\u00f6r\u00fcnt\u00fcleyici Nas\u0131l Yap\u0131l\u0131r?","isPartOf":{"@id":"https:\/\/fatihsoysal.com\/blog\/#website"},"datePublished":"2025-11-13T01:31:27+00:00","description":"Go programlama dili kullanarak kendi konsol tabanl\u0131 metin g\u00f6r\u00fcnt\u00fcleyicinizi geli\u015ftirmek ister misiniz? Bu detayl\u0131 rehberde, s\u0131f\u0131rdan ba\u015flayarak g\u00fc\u00e7l\u00fc ve verimli bir metin g\u00f6r\u00fcnt\u00fcleyici olu\u015fturman\u0131n ad\u0131mlar\u0131n\u0131 ke\u015ffedecek, b\u00fcy\u00fck dosyalar\u0131 kolayca incelemenizi sa\u011flayacak teknikleri ve ipu\u00e7lar\u0131n\u0131 \u00f6\u011freneceksiniz. Modern geli\u015ftirme ortamlar\u0131nda s\u0131kl\u0131kla kar\u015f\u0131la\u015f\u0131lan bu ihtiyaca y\u00f6nelik pratik \u00e7\u00f6z\u00fcmlerle, Go'nun performans\u0131n\u0131 ve sadeli\u011fini bir araya getiren bir ara\u00e7 in\u015fa edece\u011fiz.","breadcrumb":{"@id":"https:\/\/fatihsoysal.com\/blog\/go-ile-konsol-tabanli-metin-goruntuleyici-nasil-yapilir\/#breadcrumb"},"inLanguage":"tr","potentialAction":[{"@type":"ReadAction","target":["https:\/\/fatihsoysal.com\/blog\/go-ile-konsol-tabanli-metin-goruntuleyici-nasil-yapilir\/"]}]},{"@type":"BreadcrumbList","@id":"https:\/\/fatihsoysal.com\/blog\/go-ile-konsol-tabanli-metin-goruntuleyici-nasil-yapilir\/#breadcrumb","itemListElement":[{"@type":"ListItem","position":1,"name":"Anasayfa","item":"https:\/\/fatihsoysal.com\/blog\/"},{"@type":"ListItem","position":2,"name":"Go ile Konsol Tabanl\u0131 Metin G\u00f6r\u00fcnt\u00fcleyici Nas\u0131l Yap\u0131l\u0131r?"}]},{"@type":"WebSite","@id":"https:\/\/fatihsoysal.com\/blog\/#website","url":"https:\/\/fatihsoysal.com\/blog\/","name":"Fatihsoysal.com","description":"Blog - Yaz\u0131l\u0131m D\u00fcnyas\u0131 Tecr\u00fcbelerim","publisher":{"@id":"https:\/\/fatihsoysal.com\/blog\/#\/schema\/person\/002a254750921dcfd568a99e48240dd1"},"potentialAction":[{"@type":"SearchAction","target":{"@type":"EntryPoint","urlTemplate":"https:\/\/fatihsoysal.com\/blog\/?s={search_term_string}"},"query-input":{"@type":"PropertyValueSpecification","valueRequired":true,"valueName":"search_term_string"}}],"inLanguage":"tr"},{"@type":["Person","Organization"],"@id":"https:\/\/fatihsoysal.com\/blog\/#\/schema\/person\/002a254750921dcfd568a99e48240dd1","name":"Fatih Soysal","image":{"@type":"ImageObject","inLanguage":"tr","@id":"https:\/\/fatihsoysal.com\/blog\/#\/schema\/person\/image\/","url":"https:\/\/fatihsoysal.com\/blog\/wp-content\/uploads\/2024\/04\/cropped-replicate-prediction-3kgg1hgjn5rgp0cf0p5tr0jw7w-1.png","contentUrl":"https:\/\/fatihsoysal.com\/blog\/wp-content\/uploads\/2024\/04\/cropped-replicate-prediction-3kgg1hgjn5rgp0cf0p5tr0jw7w-1.png","width":512,"height":512,"caption":"Fatih Soysal"},"logo":{"@id":"https:\/\/fatihsoysal.com\/blog\/#\/schema\/person\/image\/"},"description":"Kullan\u0131m ve kodlama m\u00fckemmeliyetini odak alan uygulamalar olu\u015fturma deneyimine sahip, profesyonel olarak 15+ y\u0131l \u00fczeri deneyime sahip bir yaz\u0131l\u0131m m\u00fchendisi.","url":"https:\/\/fatihsoysal.com\/blog\/author\/fatihsoysal\/"}]}},"yoast_meta":{"yoast_wpseo_title":"","yoast_wpseo_metadesc":"","yoast_wpseo_canonical":""},"amp_enabled":true,"_links":{"self":[{"href":"https:\/\/fatihsoysal.com\/blog\/wp-json\/wp\/v2\/posts\/34219","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/fatihsoysal.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/fatihsoysal.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/fatihsoysal.com\/blog\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/fatihsoysal.com\/blog\/wp-json\/wp\/v2\/comments?post=34219"}],"version-history":[{"count":0,"href":"https:\/\/fatihsoysal.com\/blog\/wp-json\/wp\/v2\/posts\/34219\/revisions"}],"wp:attachment":[{"href":"https:\/\/fatihsoysal.com\/blog\/wp-json\/wp\/v2\/media?parent=34219"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/fatihsoysal.com\/blog\/wp-json\/wp\/v2\/categories?post=34219"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/fatihsoysal.com\/blog\/wp-json\/wp\/v2\/tags?post=34219"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}