| PasteRack.org | ||
| Paste # 7071 | ||
| 2016-03-22 12:11:52 | ||
Fork as a new paste. | ||
Paste viewed 344 times. | ||
Tweet | ||
Embed: | ||
;-----------------------------------------------------------------------------
; [2016-03-19] Challenge #258 [Hard]
; IRC: Interactivity
;
; Tetsumi <tetsumi@vmail.me>
;
; Compatible with
; RACKET
;-----------------------------------------------------------------------------
#lang racket/gui
(require racket/tcp racket/date)
(define-values (address port) (apply values (string-split (read-line) ":")))
(define nickname (read-line))
(define username (read-line))
(define realname (read-line))
(define serverEditor (new text% [auto-wrap #t]))
(define pmEditor (new text% [auto-wrap #t]))
(define channels (make-hash (list (cons "Server" (cons serverEditor (set)))
(cons nickname (cons pmEditor (set))))))
(define (onTabSwitch field event)
(define sel (send tabPanel get-selection))
(define chanData (hash-ref channels (send
tabPanel
get-item-label
sel)))
(define shown? (send usersListBox is-shown?))
(if (>= 1 sel)
(when shown? (send tabHorPanel delete-child usersListBox))
(unless shown?
(send tabHorPanel add-child usersListBox)))
(send editorBox
set-editor
(car chanData))
(send (car chanData) move-position 'end)
(updateusersListBox (cdr chanData)))
(define frame (new frame% [label "DP 258 Hard"]))
(define tabPanel (new tab-panel%
[parent frame]
[choices (list "Server" nickname)]
[callback onTabSwitch]))
(define tabHorPanel (new horizontal-panel%
[parent tabPanel]))
(define editorBox (new editor-canvas%
[parent tabHorPanel]
[editor serverEditor]
[style '(no-hscroll no-border)]))
(define usersListBox (new list-box%
[label #f]
[parent tabHorPanel]
[choices null]
[style (list 'single
'column-headers
'deleted)]
[columns '("Users")]
[stretchable-width #f]))
(define (handleInput s)
(define curTab (send tabPanel get-item-label (send tabPanel get-selection)))
(define split (regexp-match #px"(/)?(\\S+)? ?(\\S+)? ?(.+)?" s))
(define cmd? (second split))
(define cmd (third split))
(define arg (fourth split))
(define mes (fifth split))
(if cmd?
(case cmd
[("join") (when arg (sendMsg (JOIN arg)))]
[("part") (if arg (sendMsg (PART arg)) (sendMsg (PART curTab)))]
[("quit") (sendMsg "QUIT") (exit)]
[("msg")
(when (and arg mes)
(sendMsg (PRIVMSG arg mes))
(editorInsert pmEditor
(string-append "--> ( " arg " ) " mes "\n")))])
(unless (or (string=? curTab nickname) (string=? curTab "Server"))
(sendMsg (PRIVMSG curTab s))
(editorInsert (car (hash-ref channels curTab))
(string-append "( " nickname " ) " s "\n")))))
(define inputBox (new text-field%
[parent frame]
[label #f]
[callback
(lambda (tf event)
(when (eq? (send event get-event-type) 'text-field-enter)
(define ted (send tf get-editor))
(define t (send ted get-text))
(unless (string=? "" t)
(handleInput t)
(send ted erase))))]))
(define (editorInsert editor str)
(define d (current-date))
(define (f s) (~a s #:width 2 #:align 'right #:pad-string "0"))
(send* editor
(move-position 'end)
(lock #f)
(insert (string-append "["
(f (date-hour d))
":"
(f (date-minute d))
"] "
str))
(lock #t)))
(define (updateusersListBox s)
(send usersListBox set (sort (set->list s) string<?)))
(define (USER user mode realname)
(string-append "USER " user " " mode " :" realname))
(define JOIN
(case-lambda
[(channels) (string-append "JOIN " channels)]
[(channels keys) (string-append "JOIN " channels " " keys)]))
(define (PONG server) (string-append "PONG :" server))
(define (NICK nickname) (string-append "NICK " nickname))
(define (PRIVMSG target text) (string-append "PRIVMSG " target " :" text))
(define (PART channel) (string-append "PART " channel))
(define-values (in out) (tcp-connect address (string->number port)))
(define (sendMsg msg)
(printf "< ~a~n" msg)
(fprintf out "~a\r\n" msg)
(flush-output out))
(define (parseMsg str)
(define strSplit
(regexp-match
#px"^(?:[:](\\S+) )?(\\S+)(?: (?!:)(.+?))?(?: (?!:)(.+?))?(?: [:](.+))?$"
str))
(define num (string->number (list-ref strSplit 2)))
(apply values (if num (list-set strSplit 2 num) strSplit)))
(define (handleMsg msg)
(printf "> ~a~n" msg)
(define-values (str prefix command dest params mes) (parseMsg msg))
(define (userHas editor nick caption)
(editorInsert editor (string-append "* " nick " has " caption " *\n")))
(define (nickPrefix) (car (string-split prefix "!")))
(case command
[(353)
(set-union!
(cdr (hash-ref channels (cadr (string-split params))))
(list->set (string-split mes)))]
[("JOIN")
(unless (hash-has-key? channels dest)
(hash-set! channels dest (cons (new text% [auto-wrap #t])
(mutable-set)))
(send tabPanel append dest))
(define channelData (hash-ref channels dest))
(define editor (car channelData))
(define s (cdr channelData))
(define nick (nickPrefix))
(set-add! s nick)
(when (string=? dest (send
tabPanel
get-item-label
(send tabPanel get-selection)))
(updateusersListBox s))
(userHas editor nick "joined")]
[("PART")
(define channelData (hash-ref channels dest))
(define editor (car channelData))
(define s (cdr channelData))
(define nick (nickPrefix))
(if (string=? nick nickname)
(begin (hash-remove! channels dest)
(for/first ([i (send tabPanel get-number)]
#:when (string=? dest
(send tabPanel get-item-label i)))
(send tabPanel delete i)
(onTabSwitch #f #f)))
(begin (set-remove! s nick)
(when (string=? dest
(send tabPanel get-item-label (send
tabPanel
get-selection)))
(updateusersListBox s))
(userHas editor nick "left")))]
[("PING")
(sendMsg (PONG mes))]
[("PRIVMSG")
(editorInsert (car (hash-ref channels dest))
(string-append "( " (nickPrefix) " ) " mes "\n"))]
[else
(editorInsert
serverEditor
(string-join (filter values (list ">" params mes "\n"))))]))
(define (loop)
(define msg (read-line in 'return-linefeed))
(when (not (eof-object? msg))
(handleMsg msg)
(loop)))
(send frame show #t)
(sendMsg (NICK nickname))
(sendMsg (USER username "0 *" realname))
(thread loop)