add syntax
This commit is contained in:
610
_syntaxes/Nix.sublime-syntax
Normal file
610
_syntaxes/Nix.sublime-syntax
Normal file
@@ -0,0 +1,610 @@
|
||||
%YAML 1.2
|
||||
---
|
||||
# http://www.sublimetext.com/docs/3/syntax.html
|
||||
# 'borrowed' from Yola syntaxes on 2025 12 18
|
||||
name: Nix
|
||||
file_extensions:
|
||||
- nix
|
||||
scope: source.nix
|
||||
contexts:
|
||||
main:
|
||||
- include: expression
|
||||
comment:
|
||||
- match: '/\*([^*]|\*[^\/])*'
|
||||
push:
|
||||
- meta_scope: comment.block.nix
|
||||
- match: \*\/
|
||||
pop: true
|
||||
- include: comment-remark
|
||||
- match: '\#'
|
||||
push:
|
||||
- meta_scope: comment.line.number-sign.nix
|
||||
- match: $
|
||||
pop: true
|
||||
- include: comment-remark
|
||||
attribute-bind:
|
||||
- include: attribute-name
|
||||
- include: attribute-bind-from-equals
|
||||
attribute-bind-from-equals:
|
||||
- match: \=
|
||||
captures:
|
||||
0: keyword.operator.bind.nix
|
||||
push:
|
||||
- match: \;
|
||||
captures:
|
||||
0: punctuation.terminator.bind.nix
|
||||
pop: true
|
||||
- include: expression
|
||||
attribute-inherit:
|
||||
- match: \binherit\b
|
||||
captures:
|
||||
0: keyword.other.inherit.nix
|
||||
push:
|
||||
- match: \;
|
||||
captures:
|
||||
0: punctuation.terminator.inherit.nix
|
||||
pop: true
|
||||
- match: \(
|
||||
captures:
|
||||
0: punctuation.section.function.arguments.nix
|
||||
push:
|
||||
- match: (?=\;)
|
||||
pop: true
|
||||
- match: \)
|
||||
captures:
|
||||
0: punctuation.section.function.arguments.nix
|
||||
push:
|
||||
- match: (?=\;)
|
||||
pop: true
|
||||
- include: bad-reserved
|
||||
- include: attribute-name-single
|
||||
- include: others
|
||||
- include: expression
|
||||
- match: '(?=[a-zA-Z\_])'
|
||||
push:
|
||||
- match: (?=\;)
|
||||
pop: true
|
||||
- include: bad-reserved
|
||||
- include: attribute-name-single
|
||||
- include: others
|
||||
- include: others
|
||||
attribute-name:
|
||||
- match: '\b[a-zA-Z\_][a-zA-Z0-9\_\''\-]*'
|
||||
scope: entity.other.attribute-name.multipart.nix
|
||||
- match: \.
|
||||
- include: string-quoted
|
||||
- include: interpolation
|
||||
attribute-name-single:
|
||||
- match: '\b[a-zA-Z\_][a-zA-Z0-9\_\''\-]*'
|
||||
scope: entity.other.attribute-name.single.nix
|
||||
attrset-contents:
|
||||
- include: attribute-inherit
|
||||
- include: bad-reserved
|
||||
- include: attribute-bind
|
||||
- include: others
|
||||
attrset-definition:
|
||||
- match: '(?=\{)'
|
||||
push:
|
||||
- match: '(?=([\])};,]|\b(else|then)\b))'
|
||||
pop: true
|
||||
- match: '(\{)'
|
||||
captures:
|
||||
0: punctuation.definition.attrset.nix
|
||||
push:
|
||||
- match: '(\})'
|
||||
captures:
|
||||
0: punctuation.definition.attrset.nix
|
||||
pop: true
|
||||
- include: attrset-contents
|
||||
- match: '(?<=\})'
|
||||
push:
|
||||
- match: '(?=([\])};,]|\b(else|then)\b))'
|
||||
pop: true
|
||||
- include: expression-cont
|
||||
attrset-definition-brace-opened:
|
||||
- match: '(?<=\})'
|
||||
push:
|
||||
- match: '(?=([\])};,]|\b(else|then)\b))'
|
||||
pop: true
|
||||
- include: expression-cont
|
||||
- match: (?=.?)
|
||||
push:
|
||||
- match: '\}'
|
||||
captures:
|
||||
0: punctuation.definition.attrset.nix
|
||||
pop: true
|
||||
- include: attrset-contents
|
||||
attrset-for-sure:
|
||||
- match: (?=\brec\b)
|
||||
push:
|
||||
- match: '(?=([\])};,]|\b(else|then)\b))'
|
||||
pop: true
|
||||
- match: \brec\b
|
||||
captures:
|
||||
0: keyword.other.nix
|
||||
push:
|
||||
- match: '(?=\{)'
|
||||
pop: true
|
||||
- include: others
|
||||
- include: attrset-definition
|
||||
- include: others
|
||||
- match: '(?=\{\s*(\}|[^,?]*(=|;)))'
|
||||
push:
|
||||
- match: '(?=([\])};,]|\b(else|then)\b))'
|
||||
pop: true
|
||||
- include: attrset-definition
|
||||
- include: others
|
||||
attrset-or-function:
|
||||
- match: '\{'
|
||||
captures:
|
||||
0: punctuation.definition.attrset-or-function.nix
|
||||
push:
|
||||
- match: '(?=([\])};]|\b(else|then)\b))'
|
||||
pop: true
|
||||
- match: '(?=(\s*\}|\"|\binherit\b|\b[a-zA-Z\_][a-zA-Z0-9\_\''\-]*(\s*\.|\s*=[^=])|\$\{[a-zA-z0-9\_\''\-]+\}(\s*\.|\s*=[^=])))'
|
||||
push:
|
||||
- match: '(?=([\])};,]|\b(else|then)\b))'
|
||||
pop: true
|
||||
- include: attrset-definition-brace-opened
|
||||
- match: '(?=(\.\.\.|\b[a-zA-Z\_][a-zA-Z0-9\_\''\-]*\s*[,?]))'
|
||||
push:
|
||||
- match: '(?=([\])};,]|\b(else|then)\b))'
|
||||
pop: true
|
||||
- include: function-definition-brace-opened
|
||||
- include: bad-reserved
|
||||
- match: '\b[a-zA-Z\_][a-zA-Z0-9\_\''\-]*'
|
||||
captures:
|
||||
0: variable.parameter.function.maybe.nix
|
||||
push:
|
||||
- match: '(?=([\])};]|\b(else|then)\b))'
|
||||
pop: true
|
||||
- match: (?=\.)
|
||||
push:
|
||||
- match: '(?=([\])};,]|\b(else|then)\b))'
|
||||
pop: true
|
||||
- include: attrset-definition-brace-opened
|
||||
- match: \s*(\,)
|
||||
captures:
|
||||
1: keyword.operator.nix
|
||||
push:
|
||||
- match: '(?=([\])};,]|\b(else|then)\b))'
|
||||
pop: true
|
||||
- include: function-definition-brace-opened
|
||||
- match: (?=\=)
|
||||
push:
|
||||
- match: '(?=([\])};,]|\b(else|then)\b))'
|
||||
pop: true
|
||||
- include: attribute-bind-from-equals
|
||||
- include: attrset-definition-brace-opened
|
||||
- match: (?=\?)
|
||||
push:
|
||||
- match: '(?=([\])};,]|\b(else|then)\b))'
|
||||
pop: true
|
||||
- include: function-parameter-default
|
||||
- match: \,
|
||||
captures:
|
||||
0: keyword.operator.nix
|
||||
push:
|
||||
- match: '(?=([\])};,]|\b(else|then)\b))'
|
||||
pop: true
|
||||
- include: function-definition-brace-opened
|
||||
- include: others
|
||||
- include: others
|
||||
bad-reserved:
|
||||
- match: '(?<![\w''-])(if|then|else|assert|with|let|in|rec|inherit)(?![\w''-])'
|
||||
scope: invalid.illegal.reserved.nix
|
||||
comment-remark:
|
||||
- match: (TODO|FIXME|BUG|\!\!\!):?
|
||||
captures:
|
||||
1: markup.bold.comment.nix
|
||||
constants:
|
||||
- match: \b(builtins|true|false|null)\b
|
||||
captures:
|
||||
0: constant.language.nix
|
||||
push:
|
||||
- match: '(?=([\])};,]|\b(else|then)\b))'
|
||||
pop: true
|
||||
- include: expression-cont
|
||||
- match: \b(scopedImport|import|isNull|abort|throw|baseNameOf|dirOf|removeAttrs|map|toString|derivationStrict|derivation)\b
|
||||
captures:
|
||||
0: support.function.nix
|
||||
push:
|
||||
- match: '(?=([\])};,]|\b(else|then)\b))'
|
||||
pop: true
|
||||
- include: expression-cont
|
||||
- match: '\b[0-9]+\b'
|
||||
captures:
|
||||
0: constant.numeric.nix
|
||||
push:
|
||||
- match: '(?=([\])};,]|\b(else|then)\b))'
|
||||
pop: true
|
||||
- include: expression-cont
|
||||
expression:
|
||||
- include: parens-and-cont
|
||||
- include: list-and-cont
|
||||
- include: string
|
||||
- include: interpolation
|
||||
- include: with-assert
|
||||
- include: function-for-sure
|
||||
- include: attrset-for-sure
|
||||
- include: attrset-or-function
|
||||
- include: let
|
||||
- include: if
|
||||
- include: operator-unary
|
||||
- include: constants
|
||||
- include: bad-reserved
|
||||
- include: parameter-name-and-cont
|
||||
- include: others
|
||||
expression-cont:
|
||||
- match: (?=.?)
|
||||
push:
|
||||
- match: '(?=([\])};,]|\b(else|then)\b))'
|
||||
pop: true
|
||||
- include: parens
|
||||
- include: list
|
||||
- include: string
|
||||
- include: interpolation
|
||||
- include: function-for-sure
|
||||
- include: attrset-for-sure
|
||||
- include: attrset-or-function
|
||||
- match: '(\bor\b|\.|==|!=|!|\<\=|\<|\>\=|\>|&&|\|\||-\>|//|\?|\+\+|-|\*|/(?=([^*]|$))|\+)'
|
||||
scope: keyword.operator.nix
|
||||
- include: constants
|
||||
- include: bad-reserved
|
||||
- include: parameter-name
|
||||
- include: others
|
||||
function-body:
|
||||
- match: '(@\s*([a-zA-Z\_][a-zA-Z0-9\_\''\-]*)\s*)?(\:)'
|
||||
push:
|
||||
- match: '(?=([\])};,]|\b(else|then)\b))'
|
||||
pop: true
|
||||
- include: expression
|
||||
function-body-from-colon:
|
||||
- match: (\:)
|
||||
captures:
|
||||
0: punctuation.definition.function.nix
|
||||
push:
|
||||
- match: '(?=([\])};,]|\b(else|then)\b))'
|
||||
pop: true
|
||||
- include: expression
|
||||
function-contents:
|
||||
- include: bad-reserved
|
||||
- include: function-parameter
|
||||
- include: others
|
||||
function-definition:
|
||||
- match: (?=.?)
|
||||
push:
|
||||
- match: '(?=([\])};,]|\b(else|then)\b))'
|
||||
pop: true
|
||||
- include: function-body-from-colon
|
||||
- match: (?=.?)
|
||||
push:
|
||||
- match: (?=\:)
|
||||
pop: true
|
||||
- match: '(\b[a-zA-Z\_][a-zA-Z0-9\_\''\-]*)'
|
||||
captures:
|
||||
0: variable.parameter.function.4.nix
|
||||
push:
|
||||
- match: (?=\:)
|
||||
pop: true
|
||||
- match: \@
|
||||
push:
|
||||
- match: (?=\:)
|
||||
pop: true
|
||||
- include: function-header-until-colon-no-arg
|
||||
- include: others
|
||||
- include: others
|
||||
- match: '(?=\{)'
|
||||
push:
|
||||
- match: (?=\:)
|
||||
pop: true
|
||||
- include: function-header-until-colon-with-arg
|
||||
- include: others
|
||||
function-definition-brace-opened:
|
||||
- match: (?=.?)
|
||||
push:
|
||||
- match: '(?=([\])};,]|\b(else|then)\b))'
|
||||
pop: true
|
||||
- include: function-body-from-colon
|
||||
- match: (?=.?)
|
||||
push:
|
||||
- match: (?=\:)
|
||||
pop: true
|
||||
- include: function-header-close-brace-with-arg
|
||||
- match: (?=.?)
|
||||
push:
|
||||
- match: '(?=\})'
|
||||
pop: true
|
||||
- include: function-contents
|
||||
- include: others
|
||||
function-for-sure:
|
||||
- match: '(?=(\b[a-zA-Z\_][a-zA-Z0-9\_\''\-]*\s*[:@]|\{[^}]*\}\s*:|\{[^#}"''/=]*[,\?]))'
|
||||
push:
|
||||
- match: '(?=([\])};,]|\b(else|then)\b))'
|
||||
pop: true
|
||||
- include: function-definition
|
||||
function-header-close-brace-no-arg:
|
||||
- match: '\}'
|
||||
captures:
|
||||
0: punctuation.definition.entity.function.nix
|
||||
push:
|
||||
- match: (?=\:)
|
||||
pop: true
|
||||
- include: others
|
||||
function-header-close-brace-with-arg:
|
||||
- match: '\}'
|
||||
captures:
|
||||
0: punctuation.definition.entity.function.nix
|
||||
push:
|
||||
- match: (?=\:)
|
||||
pop: true
|
||||
- include: function-header-terminal-arg
|
||||
- include: others
|
||||
function-header-open-brace:
|
||||
- match: '\{'
|
||||
captures:
|
||||
0: punctuation.definition.entity.function.2.nix
|
||||
push:
|
||||
- match: '(?=\})'
|
||||
pop: true
|
||||
- include: function-contents
|
||||
function-header-terminal-arg:
|
||||
- match: (?=@)
|
||||
push:
|
||||
- match: (?=\:)
|
||||
pop: true
|
||||
- match: \@
|
||||
push:
|
||||
- match: (?=\:)
|
||||
pop: true
|
||||
- match: '(\b[a-zA-Z\_][a-zA-Z0-9\_\''\-]*)'
|
||||
push:
|
||||
- meta_scope: variable.parameter.function.3.nix
|
||||
- match: (?=\:)
|
||||
pop: true
|
||||
- include: others
|
||||
- include: others
|
||||
function-header-until-colon-no-arg:
|
||||
- match: '(?=\{)'
|
||||
push:
|
||||
- match: (?=\:)
|
||||
pop: true
|
||||
- include: function-header-open-brace
|
||||
- include: function-header-close-brace-no-arg
|
||||
function-header-until-colon-with-arg:
|
||||
- match: '(?=\{)'
|
||||
push:
|
||||
- match: (?=\:)
|
||||
pop: true
|
||||
- include: function-header-open-brace
|
||||
- include: function-header-close-brace-with-arg
|
||||
function-parameter:
|
||||
- match: (\.\.\.)
|
||||
push:
|
||||
- meta_scope: keyword.operator.nix
|
||||
- match: '(,|(?=\}))'
|
||||
pop: true
|
||||
- include: others
|
||||
- match: '\b[a-zA-Z\_][a-zA-Z0-9\_\''\-]*'
|
||||
captures:
|
||||
0: variable.parameter.function.1.nix
|
||||
push:
|
||||
- match: '(,|(?=\}))'
|
||||
captures:
|
||||
0: keyword.operator.nix
|
||||
pop: true
|
||||
- include: whitespace
|
||||
- include: comment
|
||||
- include: function-parameter-default
|
||||
- include: expression
|
||||
- include: others
|
||||
function-parameter-default:
|
||||
- match: \?
|
||||
captures:
|
||||
0: keyword.operator.nix
|
||||
push:
|
||||
- match: "(?=[,}])"
|
||||
pop: true
|
||||
- include: expression
|
||||
if:
|
||||
- match: (?=\bif\b)
|
||||
push:
|
||||
- match: '(?=([\])};,]|\b(else|then)\b))'
|
||||
pop: true
|
||||
- match: \bif\b
|
||||
captures:
|
||||
0: keyword.other.nix
|
||||
push:
|
||||
- match: \bth(?=en\b)
|
||||
captures:
|
||||
0: keyword.other.nix
|
||||
pop: true
|
||||
- include: expression
|
||||
- match: (?<=th)en\b
|
||||
captures:
|
||||
0: keyword.other.nix
|
||||
push:
|
||||
- match: \bel(?=se\b)
|
||||
captures:
|
||||
0: keyword.other.nix
|
||||
pop: true
|
||||
- include: expression
|
||||
- match: (?<=el)se\b
|
||||
captures:
|
||||
0: keyword.other.nix
|
||||
push:
|
||||
- match: '(?=([\])};,]|\b(else|then)\b))'
|
||||
captures:
|
||||
0: keyword.other.nix
|
||||
pop: true
|
||||
- include: expression
|
||||
illegal:
|
||||
- match: .
|
||||
scope: invalid.illegal
|
||||
interpolation:
|
||||
- match: '\$\{'
|
||||
captures:
|
||||
0: punctuation.section.embedded.begin.nix
|
||||
push:
|
||||
- meta_scope: markup.italic
|
||||
- match: '\}'
|
||||
captures:
|
||||
0: punctuation.section.embedded.end.nix
|
||||
pop: true
|
||||
- include: expression
|
||||
let:
|
||||
- match: (?=\blet\b)
|
||||
push:
|
||||
- match: '(?=([\])};,]|\b(else|then)\b))'
|
||||
pop: true
|
||||
- match: \blet\b
|
||||
captures:
|
||||
0: keyword.other.nix
|
||||
push:
|
||||
- match: '(?=([\])};,]|\b(in|else|then)\b))'
|
||||
pop: true
|
||||
- match: '(?=\{)'
|
||||
push:
|
||||
- match: '(?=([\])};,]|\b(else|then)\b))'
|
||||
pop: true
|
||||
- match: '\{'
|
||||
push:
|
||||
- match: '\}'
|
||||
pop: true
|
||||
- include: attrset-contents
|
||||
- match: '(^|(?<=\}))'
|
||||
push:
|
||||
- match: '(?=([\])};,]|\b(else|then)\b))'
|
||||
pop: true
|
||||
- include: expression-cont
|
||||
- include: others
|
||||
- include: attrset-contents
|
||||
- include: others
|
||||
- match: \bin\b
|
||||
captures:
|
||||
0: keyword.other.nix
|
||||
push:
|
||||
- match: '(?=([\])};,]|\b(else|then)\b))'
|
||||
pop: true
|
||||
- include: expression
|
||||
list:
|
||||
- match: '\['
|
||||
captures:
|
||||
0: punctuation.definition.list.nix
|
||||
push:
|
||||
- match: '\]'
|
||||
captures:
|
||||
0: punctuation.definition.list.nix
|
||||
pop: true
|
||||
- include: expression
|
||||
list-and-cont:
|
||||
- match: '(?=\[)'
|
||||
push:
|
||||
- match: '(?=([\])};,]|\b(else|then)\b))'
|
||||
pop: true
|
||||
- include: list
|
||||
- include: expression-cont
|
||||
operator-unary:
|
||||
- match: (!|-)
|
||||
scope: keyword.operator.unary.nix
|
||||
others:
|
||||
- include: whitespace
|
||||
- include: comment
|
||||
- include: illegal
|
||||
parameter-name:
|
||||
- match: '\b[a-zA-Z\_][a-zA-Z0-9\_\''\-]*'
|
||||
captures:
|
||||
0: variable.parameter.name.nix
|
||||
parameter-name-and-cont:
|
||||
- match: '\b[a-zA-Z\_][a-zA-Z0-9\_\''\-]*'
|
||||
captures:
|
||||
0: variable.parameter.name.nix
|
||||
push:
|
||||
- match: '(?=([\])};,]|\b(else|then)\b))'
|
||||
pop: true
|
||||
- include: expression-cont
|
||||
parens:
|
||||
- match: \(
|
||||
captures:
|
||||
0: punctuation.definition.expression.nix
|
||||
push:
|
||||
- match: \)
|
||||
captures:
|
||||
0: punctuation.definition.expression.nix
|
||||
pop: true
|
||||
- include: expression
|
||||
parens-and-cont:
|
||||
- match: (?=\()
|
||||
push:
|
||||
- match: '(?=([\])};,]|\b(else|then)\b))'
|
||||
pop: true
|
||||
- include: parens
|
||||
- include: expression-cont
|
||||
string:
|
||||
- match: (?=\'\')
|
||||
push:
|
||||
- match: '(?=([\])};,]|\b(else|then)\b))'
|
||||
pop: true
|
||||
- match: \'\'
|
||||
captures:
|
||||
0: punctuation.definition.string.other.start.nix
|
||||
push:
|
||||
- meta_scope: string.quoted.other.nix
|
||||
- match: \'\'(?!\$|\'|\\.)
|
||||
captures:
|
||||
0: punctuation.definition.string.other.end.nix
|
||||
pop: true
|
||||
- match: \'\'(\$|\'|\\.)
|
||||
scope: constant.character.escape.nix
|
||||
- include: interpolation
|
||||
- include: expression-cont
|
||||
- match: (?=\")
|
||||
push:
|
||||
- match: '(?=([\])};,]|\b(else|then)\b))'
|
||||
pop: true
|
||||
- include: string-quoted
|
||||
- include: expression-cont
|
||||
- match: '(~?[a-zA-Z0-9\.\_\-\+]*(\/[a-zA-Z0-9\.\_\-\+]+)+)'
|
||||
captures:
|
||||
0: string.unquoted.path.nix
|
||||
push:
|
||||
- match: '(?=([\])};,]|\b(else|then)\b))'
|
||||
pop: true
|
||||
- include: expression-cont
|
||||
- match: '(\<[a-zA-Z0-9\.\_\-\+]+(\/[a-zA-Z0-9\.\_\-\+]+)*\>)'
|
||||
captures:
|
||||
0: string.unquoted.spath.nix
|
||||
push:
|
||||
- match: '(?=([\])};,]|\b(else|then)\b))'
|
||||
pop: true
|
||||
- include: expression-cont
|
||||
- match: '([a-zA-Z][a-zA-Z0-9\+\-\.]*\:[a-zA-Z0-9\%\/\?\:\@\&\=\+\$\,\-\_\.\!\~\*\'']+)'
|
||||
captures:
|
||||
0: string.unquoted.url.nix
|
||||
push:
|
||||
- match: '(?=([\])};,]|\b(else|then)\b))'
|
||||
pop: true
|
||||
- include: expression-cont
|
||||
string-quoted:
|
||||
- match: \"
|
||||
captures:
|
||||
0: punctuation.definition.string.double.start.nix
|
||||
push:
|
||||
- meta_scope: string.quoted.double.nix
|
||||
- match: \"
|
||||
captures:
|
||||
0: punctuation.definition.string.double.end.nix
|
||||
pop: true
|
||||
- match: \\.
|
||||
scope: constant.character.escape.nix
|
||||
- include: interpolation
|
||||
whitespace:
|
||||
- match: \s+
|
||||
with-assert:
|
||||
- match: '(?<![\w''-])(with|assert)(?![\w''-])'
|
||||
captures:
|
||||
0: keyword.other.nix
|
||||
push:
|
||||
- match: \;
|
||||
pop: true
|
||||
- include: expression
|
||||
121
posts/20251218-glsl-edsl-p1.md
Normal file
121
posts/20251218-glsl-edsl-p1.md
Normal file
@@ -0,0 +1,121 @@
|
||||
---
|
||||
layout: default.liquid
|
||||
|
||||
title: 2025-12-18 GLSL EDSL in Haskell part 1
|
||||
description: first part of GLSL EDSL development series. We initialize the project and do some planning.
|
||||
is_draft: true
|
||||
---
|
||||
|
||||
all code for this project is available [here](https://git.mtgmonkey.net/Andromeda/hs-glsl). Please contact me if you want an account for contribution or to file issues.
|
||||
|
||||
#### goals of this project
|
||||
|
||||
I want to generate [GLSL]() from the type-safe environment of Haskell with an [EDSL](). Specifically, I want to functionally declare the glsl shader code I use in my [game](https://git.mtgmonkey.net/Andromeda/hs-game).
|
||||
|
||||
At the moment, that's quite a lot. Let's start with a practically bare Haskell/OpenGL project. Let's build our development environment.
|
||||
|
||||
``` bash
|
||||
mkdir hs-glsl
|
||||
cd hs-glsl
|
||||
|
||||
# get initial dependencies
|
||||
nix-shell -p cabal-install ghc
|
||||
cabal init
|
||||
# all defaults are ok for our needs EXCEPT the following:
|
||||
# Application directory: I chose 4 then put `src`
|
||||
# Version: I chose 0.1.0, breaking with PVP in
|
||||
# favor of Semantic Versioning
|
||||
# Category: Graphics
|
||||
# I also entered my contact, username, and homepage
|
||||
```
|
||||
|
||||
Great, now we have a `hs-glsl.cabal`, the file that defines our project. Cabal also created a number of other files and directories, namely `src/Main.hs` and `LICENSE`. Running the command `cabal run` will run the project, but it isn't reproducable; how can we do it with Nix? We can create a nix flake as follows:
|
||||
|
||||
``` nix
|
||||
# flake.nix
|
||||
{
|
||||
inputs = {
|
||||
nixpkgs.url = "nixpkgs/nixpkgs-unstable";
|
||||
};
|
||||
outputs = {
|
||||
nixpkgs, self, ...
|
||||
}: let
|
||||
system = "x86_64-linux";
|
||||
pkgs = nixpkgs.legacyPackages.${system};
|
||||
in {
|
||||
packages.${system} = {
|
||||
default =
|
||||
pkgs.haskellPackages.callCabal2nix "hs-glsl" {};
|
||||
};
|
||||
devShells.${system} = {
|
||||
default = pkgs.mkShell {
|
||||
packages = [
|
||||
pkgs.cabal-install
|
||||
];
|
||||
inputsFrom = [
|
||||
self.packages.${system}.default
|
||||
];
|
||||
};
|
||||
};
|
||||
};
|
||||
}
|
||||
```
|
||||
|
||||
now `nix develop` puts us in a shell with all of out dependencies, and `nix run` should run the program. Let's use [GLFW-b]() to create a window:
|
||||
|
||||
``` yaml
|
||||
# hs-glsl.cabal
|
||||
...
|
||||
executable hs-glsl
|
||||
...
|
||||
build-depends:
|
||||
base ^>=4.20.2.0
|
||||
, GLFW-b <1000
|
||||
...
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
``` hs
|
||||
-- | src/Main.hs
|
||||
module Main (main) where
|
||||
|
||||
-- | windowing library
|
||||
import qualified Graphics.UI.GLFW as GLFW
|
||||
|
||||
-- | main
|
||||
main :: IO ()
|
||||
main = do
|
||||
-- initialize GLFW
|
||||
_ <- GLFW.init
|
||||
GLFW.defaultWindowHints
|
||||
|
||||
-- we use GLSL version 3.3 Core here
|
||||
GLFW.windowHint $ GLFW.WindowHint'ContextVersionMajor 3
|
||||
GLFW.windowHint $ GLFW.WindowHint'ContextVersionMinor 3
|
||||
GLFW.windowHint $ GLFW.WindowHint'OpenGLProfile GLFW.OpenGLProfile'Core
|
||||
|
||||
-- monitor required to fullscreen at start
|
||||
monitor <- GLFW.getPrimaryMonitor
|
||||
|
||||
-- actually create the window
|
||||
Just window <- GLFW.createWindow 256 256 "hs-glsl" monitor Nothing
|
||||
GLFW.makeContextCurrent $ Just window
|
||||
|
||||
-- enter loop
|
||||
loop window
|
||||
|
||||
-- | loop that runs every frame
|
||||
loop :: GLFW.Window -> IO ()
|
||||
loop window = do
|
||||
-- swap to next framebuffer
|
||||
GLFW.swapBuffers window
|
||||
|
||||
-- call next frame
|
||||
loop window
|
||||
```
|
||||
|
||||
Great, a fullscreen window that never closes! I'll go ahead and add a quick key callback so that pressing `esc` closes the program.
|
||||
|
||||
```
|
||||
-- | src/Main.hs
|
||||
Reference in New Issue
Block a user